用于多个起始值和终止值的矢量化 NumPy linspace
Vectorized NumPy linspace for multiple start and stop values
我需要创建一个二维数组,其中每一行的开头和结尾可能都不同。假设给出了每一行的第一个和最后一个元素,并且所有其他元素只是根据行的长度进行插值在一个简单的例子中,假设我想创建一个 3X3 数组,其起始位置相同但结束位置不同,由下面的 W 给出:
array([[ 0., 1., 2.],
[ 0., 2., 4.],
[ 0., 3., 6.]])
有没有比以下方法更好的方法:
D=np.ones((3,3))*np.arange(0,3)
D=D/D[:,-1]
W=np.array([2,4,6]) # last element of each row assumed given
Res= (D.T*W).T
这是一种使用 broadcasting
-
的方法
def create_ranges(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
steps = (1.0/divisor) * (stop - start)
return steps[:,None]*np.arange(N) + start[:,None]
样本运行-
In [22]: # Setup start, stop for each row and no. of elems in each row
...: start = np.array([1,4,2])
...: stop = np.array([6,7,6])
...: N = 5
...:
In [23]: create_ranges(start, stop, 5)
Out[23]:
array([[ 1. , 2.25, 3.5 , 4.75, 6. ],
[ 4. , 4.75, 5.5 , 6.25, 7. ],
[ 2. , 3. , 4. , 5. , 6. ]])
In [24]: create_ranges(start, stop, 5, endpoint=False)
Out[24]:
array([[ 1. , 2. , 3. , 4. , 5. ],
[ 4. , 4.6, 5.2, 5.8, 6.4],
[ 2. , 2.8, 3.6, 4.4, 5.2]])
让我们利用多核!
我们可以利用 multi-core
with numexpr
module 处理大数据并提高内存效率和性能 -
import numexpr as ne
def create_ranges_numexpr(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
s0 = start[:,None]
s1 = stop[:,None]
r = np.arange(N)
return ne.evaluate('((1.0/divisor) * (s1 - s0))*r + s0')
与 OP 一样,linspace
的使用假设所有行的开始都是 0。
x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2)
(编辑 - 这是我应该得到的转置;转置它或切换使用 [:,None]
)
对于 N=3000,它明显比 @Divaker's
解决方案快。我不太清楚为什么。
In [132]: timeit N=3000;x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2)
10 loops, best of 3: 91.7 ms per loop
In [133]: timeit create_ranges(np.zeros(N),np.arange(0,2*N,2),N)
1 loop, best of 3: 197 ms per loop
In [134]: def foo(N):
...: D=np.ones((N,N))*np.arange(N)
...: D=D/D[:,-1]
...: W=np.arange(0,2*N,2)
...: return (D.T*W).T
...:
In [135]: timeit foo(3000)
1 loop, best of 3: 454 ms per loop
============
我可以使用开始和停止:
In [201]: starts=np.array([1,4,2]); stops=np.array([6,7,8])
In [202]: x=(np.linspace(0,1,5)[:,None]*(stops-starts)+starts).T
In [203]: x
Out[203]:
array([[ 1. , 2.25, 3.5 , 4.75, 6. ],
[ 4. , 4.75, 5.5 , 6.25, 7. ],
[ 2. , 3.5 , 5. , 6.5 , 8. ]])
由于额外的计算,它比 create_ranges
慢了一点。
In [208]: timeit N=3000;starts=np.zeros(N);stops=np.arange(0,2*N,2);x=(np.linspace(0,1,N)[:,None]*(stops-starts)+starts).T
1 loop, best of 3: 227 ms per loop
所有这些解决方案只是在 starts
和 stops
之间进行线性插值的想法的变体。
我根据@Divakar 的解决方案扩展了一些功能。它牺牲了一些速度,但现在兼容不同长度的 N
而不仅仅是标量。另外,这个版本比 @Saullo's sollution.
更快
def create_ranges_divak(starts, stops, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
steps = (1.0/divisor) * (stops - starts)
uni_N = np.unique(N)
if len(uni_N) == 1:
return steps[:,None]*np.arange(uni_N) + starts[:,None]
else:
return [step * np.arange(n) + start for start, step, n in zip(starts, steps, N)]
NumPy >= 1.16.0:
现在可以为 np.linspace
的 start
和 stop
参数提供 array-like 值。
对于问题中给出的示例,语法为:
>>> np.linspace((0, 0, 0), (2, 4, 6), 3, axis=1)
array([[0., 1., 2.],
[0., 2., 4.],
[0., 3., 6.]])
新 axis
参数指定生成数据的方向。默认为 0
:
>>> np.linspace((0, 0, 0), (2, 4, 6), 3)
array([[0., 0., 0.],
[1., 2., 3.],
[2., 4., 6.]])
我需要创建一个二维数组,其中每一行的开头和结尾可能都不同。假设给出了每一行的第一个和最后一个元素,并且所有其他元素只是根据行的长度进行插值在一个简单的例子中,假设我想创建一个 3X3 数组,其起始位置相同但结束位置不同,由下面的 W 给出:
array([[ 0., 1., 2.],
[ 0., 2., 4.],
[ 0., 3., 6.]])
有没有比以下方法更好的方法:
D=np.ones((3,3))*np.arange(0,3)
D=D/D[:,-1]
W=np.array([2,4,6]) # last element of each row assumed given
Res= (D.T*W).T
这是一种使用 broadcasting
-
def create_ranges(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
steps = (1.0/divisor) * (stop - start)
return steps[:,None]*np.arange(N) + start[:,None]
样本运行-
In [22]: # Setup start, stop for each row and no. of elems in each row
...: start = np.array([1,4,2])
...: stop = np.array([6,7,6])
...: N = 5
...:
In [23]: create_ranges(start, stop, 5)
Out[23]:
array([[ 1. , 2.25, 3.5 , 4.75, 6. ],
[ 4. , 4.75, 5.5 , 6.25, 7. ],
[ 2. , 3. , 4. , 5. , 6. ]])
In [24]: create_ranges(start, stop, 5, endpoint=False)
Out[24]:
array([[ 1. , 2. , 3. , 4. , 5. ],
[ 4. , 4.6, 5.2, 5.8, 6.4],
[ 2. , 2.8, 3.6, 4.4, 5.2]])
让我们利用多核!
我们可以利用 multi-core
with numexpr
module 处理大数据并提高内存效率和性能 -
import numexpr as ne
def create_ranges_numexpr(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
s0 = start[:,None]
s1 = stop[:,None]
r = np.arange(N)
return ne.evaluate('((1.0/divisor) * (s1 - s0))*r + s0')
与 OP 一样,linspace
的使用假设所有行的开始都是 0。
x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2)
(编辑 - 这是我应该得到的转置;转置它或切换使用 [:,None]
)
对于 N=3000,它明显比 @Divaker's
解决方案快。我不太清楚为什么。
In [132]: timeit N=3000;x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2)
10 loops, best of 3: 91.7 ms per loop
In [133]: timeit create_ranges(np.zeros(N),np.arange(0,2*N,2),N)
1 loop, best of 3: 197 ms per loop
In [134]: def foo(N):
...: D=np.ones((N,N))*np.arange(N)
...: D=D/D[:,-1]
...: W=np.arange(0,2*N,2)
...: return (D.T*W).T
...:
In [135]: timeit foo(3000)
1 loop, best of 3: 454 ms per loop
============
我可以使用开始和停止:
In [201]: starts=np.array([1,4,2]); stops=np.array([6,7,8])
In [202]: x=(np.linspace(0,1,5)[:,None]*(stops-starts)+starts).T
In [203]: x
Out[203]:
array([[ 1. , 2.25, 3.5 , 4.75, 6. ],
[ 4. , 4.75, 5.5 , 6.25, 7. ],
[ 2. , 3.5 , 5. , 6.5 , 8. ]])
由于额外的计算,它比 create_ranges
慢了一点。
In [208]: timeit N=3000;starts=np.zeros(N);stops=np.arange(0,2*N,2);x=(np.linspace(0,1,N)[:,None]*(stops-starts)+starts).T
1 loop, best of 3: 227 ms per loop
所有这些解决方案只是在 starts
和 stops
之间进行线性插值的想法的变体。
我根据@Divakar 的解决方案扩展了一些功能。它牺牲了一些速度,但现在兼容不同长度的 N
而不仅仅是标量。另外,这个版本比 @Saullo's sollution.
def create_ranges_divak(starts, stops, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
steps = (1.0/divisor) * (stops - starts)
uni_N = np.unique(N)
if len(uni_N) == 1:
return steps[:,None]*np.arange(uni_N) + starts[:,None]
else:
return [step * np.arange(n) + start for start, step, n in zip(starts, steps, N)]
NumPy >= 1.16.0:
现在可以为 np.linspace
的 start
和 stop
参数提供 array-like 值。
对于问题中给出的示例,语法为:
>>> np.linspace((0, 0, 0), (2, 4, 6), 3, axis=1)
array([[0., 1., 2.],
[0., 2., 4.],
[0., 3., 6.]])
新 axis
参数指定生成数据的方向。默认为 0
:
>>> np.linspace((0, 0, 0), (2, 4, 6), 3)
array([[0., 0., 0.],
[1., 2., 3.],
[2., 4., 6.]])