![](/img/trans.png)
[英]Given a 1D ndarray and an integer, what's the most efficient way to generate this ndarray?
[英]Efficient fenceposting of 1D ndarray
用numpy
将data
重塑到fencepost
的最有效方法是什么?
data = np.array([1, 2, 3, 4, 5])
fencepost = np.array([[1, 2], [2, 3], [3, 4], [4, 5]])
您可以通过不同地查看相同的数据来简单地获得相同的结果:
>>> from numpy.lib.stride_tricks import as_strided
>>> fencepost = as_strided(data, shape=(data.shape[0]-1, 2),
strides=(data.strides[0],)*2)
>>> fencepost
array([[1, 2],
[2, 3],
[3, 4],
[4, 5]])
没有数据被复制,因此特别是对于非常大的阵列,这将尽可能快。 如果确实需要单独的副本,则只需执行fencepost = fencepost.copy()
并让numpy为您内部处理所有事情:
In [11]: data = np.arange(10000000)
In [12]: %timeit as_strided(data, shape=(data.shape[0]-1, 2),
... strides=(data.strides[0],)*2)
100000 loops, best of 3: 12.2 us per loop
In [13]: %timeit as_strided(data, shape=(data.shape[0]-1, 2),
... strides=(data.strides[0],)*2).copy()
10 loops, best of 3: 183 ms per loop
这并不是真正的重塑,因为第二个数组具有不同数量的元素。 如果第一个数组具有N个元素(在这种情况下N = 5),第二个数组则具有2N-2(在这种情况下为8)。
因此,您将必须创建一个新数组并相应地填充它。 有两种方法。 您可以逐列或逐行填充。 哪个更有效取决于...以及让我们找出答案!
在这里,我使用来自IPython的%timeit,具有三种不同的数组大小:
import numpy as np
from numba import jit
data = np.array([1, 2, 3, 4, 5])
#fencepost = np.array([[1, 2], [2, 3], [3, 4], [4, 5]])
def fp1(data):
f = np.zeros((data.shape[0]-1,2))
for i in range(data.shape[0]-1):
f[i] = data[i:i+2]
return f
def fp2(data):
f = np.zeros((data.shape[0]-1,2))
f[:,0] = data[:-1]
f[:,1] = data[1:]
return f
%timeit fp1(data)
%timeit fp2(data)
data2 = np.array(range(100000))
%timeit fp1(data2)
%timeit fp2(data2)
data3 = np.array(range(10000000))
%timeit fp1(data3)
%timeit fp2(data3)
在我的计算机上,对于较小的数组,逐行执行的结果效率稍高,但是逐列快速效果要好得多(因此,fp2是有效的答案):
100000 loops, best of 3: 13 µs per loop
100000 loops, best of 3: 14.4 µs per loop
1 loops, best of 3: 203 ms per loop
1000 loops, best of 3: 1.09 ms per loop
1 loops, best of 3: 20.7 s per loop
1 loops, best of 3: 253 ms per loop
本质上,fp2更快,因为它只有2个numpy操作,而fp1是一个循环,需要多次调用numpy。 对于小型阵列,对numpy的5次调用的开销可以忽略不计。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.