如何在 Python 中的不等间距值之间创建等间距值?
How to create equal spaced values in between unequal spaced values in Python?
我有一个数组 A(变量),形式如下:
A = [1, 3, 7, 9, 15, 20, 24]
现在我想在数组 A 的值之间创建 10 个(变量)等距值,以便我得到以下形式的数组 B:
B = [1, 1.2, 1.4, ... 2.8, 3, 3.4, 3.8, ... , 6.6, 7, 7.2, ..., 23.6, 24]
本质上,B 应该始终具有 A 的值以及 A 的值之间等距的值。
我确实使用代码解决了这个问题:
import numpy as np
A = np.array([1, 3, 7, 9, 15, 20, 24])
B = []
for i in range(len(A) - 1):
B = np.append(B, np.linspace(A[i], A[i + 1], 11))
print (B)
但是 NumPy 是否已经有任何功能或者是否有其他更好的方法来创建这样的数组。
您可以在列表理解和 np.concatenate
中使用 zip
函数,但是如果您也想要最后一个元素,您可以将其附加 np.append
:
>>> np.append(np.concatenate([np.linspace(i, j, 10, False) for i,j in zip(A,A[1:])]),A[-1])
array([ 1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6,
2.8, 3. , 3.4, 3.8, 4.2, 4.6, 5. , 5.4, 5.8,
6.2, 6.6, 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2,
8.4, 8.6, 8.8, 9. , 9.6, 10.2, 10.8, 11.4, 12. ,
12.6, 13.2, 13.8, 14.4, 15. , 15.5, 16. , 16.5, 17. ,
17.5, 18. , 18.5, 19. , 19.5, 20. , 20.4, 20.8, 21.2,
21.6, 22. , 22.4, 22.8, 23.2, 23.6, 24. ])
也可以使用retstep=True
到return(samples, step),其中step是样本之间的间距。
>>> np.concatenate([np.linspace(i, j, 10, False,retstep=True) for i,j in zip(A,A[1:])])
array([array([ 1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6, 2.8]),
0.2,
array([ 3. , 3.4, 3.8, 4.2, 4.6, 5. , 5.4, 5.8, 6.2, 6.6]),
0.4,
array([ 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2, 8.4, 8.6, 8.8]),
0.2,
array([ 9. , 9.6, 10.2, 10.8, 11.4, 12. , 12.6, 13.2, 13.8, 14.4]),
0.6,
array([ 15. , 15.5, 16. , 16.5, 17. , 17.5, 18. , 18.5, 19. , 19.5]),
0.5,
array([ 20. , 20.4, 20.8, 21.2, 21.6, 22. , 22.4, 22.8, 23.2, 23.6]),
0.4], dtype=object)
基本上是您原始方法的稍微浓缩的版本:
print np.hstack(np.linspace(a, b, 10, endpoint=False) for a, b in zip(A[:-1], A[1:]))
输出:
[ 1. 1.2 1.4 1.6 1.8 2. 2.2 2.4 2.6 2.8 3. 3.4
3.8 4.2 4.6 5. 5.4 5.8 6.2 6.6 7. 7.2 7.4 7.6
7.8 8. 8.2 8.4 8.6 8.8 9. 9.6 10.2 10.8 11.4 12.
12.6 13.2 13.8 14.4 15. 15.5 16. 16.5 17. 17.5 18. 18.5
19. 19.5 20. 20.4 20.8 21.2 21.6 22. 22.4 22.8 23.2 23.6]
endpoint
参数控制在 两个原始值之间是否有 9 个或 10 个等距值 。
编辑
因为你想要 24 在最后,你可以像 Kasra 那样 append
或者 -- 提出一些变化 ;) -- 忘记 endpoint
参数并生成 10 + 1
值从 a
到 b
。这将自动附加 24(因为 endpoint
默认为 true)。
(更新: 正如 Bas Swinckels 指出的那样,您现在需要用 unique
包装它...)
print np.unique(np.hstack(np.linspace(a, b, 10 + 1) for a, b in zip(A[:-1], A[1:])))
[ 1. 1.2 1.4 1.6 1.8 2. 2.2 2.4 2.6 2.8 3.
3.4 3.8 4.2 4.6 5. 5.4 5.8 6.2 6.6 7. 7.2
7.4 7.6 7.8 8. 8.2 8.4 8.6 8.8 9 9.6 10.2
10.8 11.4 12. 12.6 13.2 13.8 14.4 15. 15.5 16. 16.5
17. 17.5 18. 18.5 19. 19.5 20. 20.4 20.8 21.2 21.6
22. 22.4 22.8 23.2 23.6 24. ]
使用 interpolation 而不是串联的替代方法:
n = 10
x = np.arange(0, n * len(A), n) # 0, 10, .., 50, 60
xx = np.arange((len(A) - 1) * n + 1) # 0, 1, .., 59, 60
B = np.interp(xx, x, A)
结果:
In [31]: B
Out[31]:
array([ 1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6,
2.8, 3. , 3.4, 3.8, 4.2, 4.6, 5. , 5.4, 5.8,
6.2, 6.6, 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2,
8.4, 8.6, 8.8, 9. , 9.6, 10.2, 10.8, 11.4, 12. ,
12.6, 13.2, 13.8, 14.4, 15. , 15.5, 16. , 16.5, 17. ,
17.5, 18. , 18.5, 19. , 19.5, 20. , 20.4, 20.8, 21.2,
21.6, 22. , 22.4, 22.8, 23.2, 23.6, 24. ])
这应该比其他解决方案更快,因为它不使用 Python for 循环,也不会多次调用 linspace
。快速时序比较:
In [58]: timeit np.interp(np.arange((len(A) - 1) * 10 + 1), np.arange(0, 10*len(A), 10), A)
100000 loops, best of 3: 10.3 µs per loop
In [59]: timeit np.append(np.concatenate([np.linspace(i, j, 10, False) for i, j in zip(A, A[1:])]), A[-1])
10000 loops, best of 3: 94.2 µs per loop
In [60]: timeit np.unique(np.hstack(np.linspace(a, b, 10 + 1) for a, b in zip(A[:-1], A[1:])))
10000 loops, best of 3: 140 µs per loop
解决方案代码
此解决方案建议使用 broadcasting
和 matrix multiplication
的矢量化方法。
基本步骤是:
将不包括1
即[0,1)
的单位步长间隔划分为步长相等且长度为steps
.[=33的元素数组=]
然后,将这些步长数组元素中的每一个乘以 A
的微分,以获得偏移插值元素的二维数组。
最后,为实际插值添加 A
个元素。
这是实现 -
out2D = (np.diff(A)[:,None]*np.arange(steps)/steps) + A[:-1,None]
out = np.append(out2D,A[-1])
基准测试
对于中型到大型输入数组,所提出的方法似乎比 中建议的实际基于插值的方法更快,因为我们正在使用常规模式来插值。这里有一些运行时测试来确认 -
案例 #1:A
长度 100
和 steps = 10
In [42]: A = np.sort(np.random.randint(1,100000,(1,100))).ravel()
In [43]: steps = 10
In [44]: %timeit interp_based(A,steps)
100000 loops, best of 3: 18.3 µs per loop
In [45]: %timeit broadcasting_based(A,steps)
100000 loops, best of 3: 19.7 µs per loop
案例 #2:A
长度 500
和 steps = 10
In [46]: A = np.sort(np.random.randint(1,100000,(1,500))).ravel()
In [47]: steps = 10
In [48]: %timeit interp_based(A,steps)
10000 loops, best of 3: 101 µs per loop
In [49]: %timeit broadcasting_based(A,steps)
10000 loops, best of 3: 48.8 µs per loop
案例 #3:A
长度 1000
和 steps = 20
In [50]: A = np.sort(np.random.randint(1,100000,(1,1000))).ravel()
In [51]: steps = 20
In [52]: %timeit interp_based(A,steps)
1000 loops, best of 3: 345 µs per loop
In [53]: %timeit broadcasting_based(A,steps)
10000 loops, best of 3: 139 µs per loop
我有一个数组 A(变量),形式如下:
A = [1, 3, 7, 9, 15, 20, 24]
现在我想在数组 A 的值之间创建 10 个(变量)等距值,以便我得到以下形式的数组 B:
B = [1, 1.2, 1.4, ... 2.8, 3, 3.4, 3.8, ... , 6.6, 7, 7.2, ..., 23.6, 24]
本质上,B 应该始终具有 A 的值以及 A 的值之间等距的值。
我确实使用代码解决了这个问题:
import numpy as np
A = np.array([1, 3, 7, 9, 15, 20, 24])
B = []
for i in range(len(A) - 1):
B = np.append(B, np.linspace(A[i], A[i + 1], 11))
print (B)
但是 NumPy 是否已经有任何功能或者是否有其他更好的方法来创建这样的数组。
您可以在列表理解和 np.concatenate
中使用 zip
函数,但是如果您也想要最后一个元素,您可以将其附加 np.append
:
>>> np.append(np.concatenate([np.linspace(i, j, 10, False) for i,j in zip(A,A[1:])]),A[-1])
array([ 1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6,
2.8, 3. , 3.4, 3.8, 4.2, 4.6, 5. , 5.4, 5.8,
6.2, 6.6, 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2,
8.4, 8.6, 8.8, 9. , 9.6, 10.2, 10.8, 11.4, 12. ,
12.6, 13.2, 13.8, 14.4, 15. , 15.5, 16. , 16.5, 17. ,
17.5, 18. , 18.5, 19. , 19.5, 20. , 20.4, 20.8, 21.2,
21.6, 22. , 22.4, 22.8, 23.2, 23.6, 24. ])
也可以使用retstep=True
到return(samples, step),其中step是样本之间的间距。
>>> np.concatenate([np.linspace(i, j, 10, False,retstep=True) for i,j in zip(A,A[1:])])
array([array([ 1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6, 2.8]),
0.2,
array([ 3. , 3.4, 3.8, 4.2, 4.6, 5. , 5.4, 5.8, 6.2, 6.6]),
0.4,
array([ 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2, 8.4, 8.6, 8.8]),
0.2,
array([ 9. , 9.6, 10.2, 10.8, 11.4, 12. , 12.6, 13.2, 13.8, 14.4]),
0.6,
array([ 15. , 15.5, 16. , 16.5, 17. , 17.5, 18. , 18.5, 19. , 19.5]),
0.5,
array([ 20. , 20.4, 20.8, 21.2, 21.6, 22. , 22.4, 22.8, 23.2, 23.6]),
0.4], dtype=object)
基本上是您原始方法的稍微浓缩的版本:
print np.hstack(np.linspace(a, b, 10, endpoint=False) for a, b in zip(A[:-1], A[1:]))
输出:
[ 1. 1.2 1.4 1.6 1.8 2. 2.2 2.4 2.6 2.8 3. 3.4
3.8 4.2 4.6 5. 5.4 5.8 6.2 6.6 7. 7.2 7.4 7.6
7.8 8. 8.2 8.4 8.6 8.8 9. 9.6 10.2 10.8 11.4 12.
12.6 13.2 13.8 14.4 15. 15.5 16. 16.5 17. 17.5 18. 18.5
19. 19.5 20. 20.4 20.8 21.2 21.6 22. 22.4 22.8 23.2 23.6]
endpoint
参数控制在 两个原始值之间是否有 9 个或 10 个等距值 。
编辑
因为你想要 24 在最后,你可以像 Kasra 那样 append
或者 -- 提出一些变化 ;) -- 忘记 endpoint
参数并生成 10 + 1
值从 a
到 b
。这将自动附加 24(因为 endpoint
默认为 true)。
(更新: 正如 Bas Swinckels 指出的那样,您现在需要用 unique
包装它...)
print np.unique(np.hstack(np.linspace(a, b, 10 + 1) for a, b in zip(A[:-1], A[1:])))
[ 1. 1.2 1.4 1.6 1.8 2. 2.2 2.4 2.6 2.8 3.
3.4 3.8 4.2 4.6 5. 5.4 5.8 6.2 6.6 7. 7.2
7.4 7.6 7.8 8. 8.2 8.4 8.6 8.8 9 9.6 10.2
10.8 11.4 12. 12.6 13.2 13.8 14.4 15. 15.5 16. 16.5
17. 17.5 18. 18.5 19. 19.5 20. 20.4 20.8 21.2 21.6
22. 22.4 22.8 23.2 23.6 24. ]
使用 interpolation 而不是串联的替代方法:
n = 10
x = np.arange(0, n * len(A), n) # 0, 10, .., 50, 60
xx = np.arange((len(A) - 1) * n + 1) # 0, 1, .., 59, 60
B = np.interp(xx, x, A)
结果:
In [31]: B
Out[31]:
array([ 1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6,
2.8, 3. , 3.4, 3.8, 4.2, 4.6, 5. , 5.4, 5.8,
6.2, 6.6, 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2,
8.4, 8.6, 8.8, 9. , 9.6, 10.2, 10.8, 11.4, 12. ,
12.6, 13.2, 13.8, 14.4, 15. , 15.5, 16. , 16.5, 17. ,
17.5, 18. , 18.5, 19. , 19.5, 20. , 20.4, 20.8, 21.2,
21.6, 22. , 22.4, 22.8, 23.2, 23.6, 24. ])
这应该比其他解决方案更快,因为它不使用 Python for 循环,也不会多次调用 linspace
。快速时序比较:
In [58]: timeit np.interp(np.arange((len(A) - 1) * 10 + 1), np.arange(0, 10*len(A), 10), A)
100000 loops, best of 3: 10.3 µs per loop
In [59]: timeit np.append(np.concatenate([np.linspace(i, j, 10, False) for i, j in zip(A, A[1:])]), A[-1])
10000 loops, best of 3: 94.2 µs per loop
In [60]: timeit np.unique(np.hstack(np.linspace(a, b, 10 + 1) for a, b in zip(A[:-1], A[1:])))
10000 loops, best of 3: 140 µs per loop
解决方案代码
此解决方案建议使用 broadcasting
和 matrix multiplication
的矢量化方法。
基本步骤是:
将不包括
1
即[0,1)
的单位步长间隔划分为步长相等且长度为steps
.[=33的元素数组=]然后,将这些步长数组元素中的每一个乘以
A
的微分,以获得偏移插值元素的二维数组。最后,为实际插值添加
A
个元素。
这是实现 -
out2D = (np.diff(A)[:,None]*np.arange(steps)/steps) + A[:-1,None]
out = np.append(out2D,A[-1])
基准测试
对于中型到大型输入数组,所提出的方法似乎比
案例 #1:A
长度 100
和 steps = 10
In [42]: A = np.sort(np.random.randint(1,100000,(1,100))).ravel()
In [43]: steps = 10
In [44]: %timeit interp_based(A,steps)
100000 loops, best of 3: 18.3 µs per loop
In [45]: %timeit broadcasting_based(A,steps)
100000 loops, best of 3: 19.7 µs per loop
案例 #2:A
长度 500
和 steps = 10
In [46]: A = np.sort(np.random.randint(1,100000,(1,500))).ravel()
In [47]: steps = 10
In [48]: %timeit interp_based(A,steps)
10000 loops, best of 3: 101 µs per loop
In [49]: %timeit broadcasting_based(A,steps)
10000 loops, best of 3: 48.8 µs per loop
案例 #3:A
长度 1000
和 steps = 20
In [50]: A = np.sort(np.random.randint(1,100000,(1,1000))).ravel()
In [51]: steps = 20
In [52]: %timeit interp_based(A,steps)
1000 loops, best of 3: 345 µs per loop
In [53]: %timeit broadcasting_based(A,steps)
10000 loops, best of 3: 139 µs per loop