我有一个NumPy数组[1,2,3,4,5,6,7,8,9,10,11,12,13,14]
,希望有一个类似[[1,2,3,4], [2,3,4,5], [3,4,5,6], ..., [11,12,13,14]]
的数组。
当然可以通过循环遍历大型数组并将长度为4的数组添加到新数组中来实现这一点,但我很好奇是否有一些秘密的“神奇”Python方法正在这样做:)
答案 0 :(得分:25)
您应该使用stride_tricks
。当我第一次看到这个时,“魔法”这个词就浮现在脑海中。它很简单,是迄今为止最快的方法。
>>> as_strided = numpy.lib.stride_tricks.as_strided
>>> a = numpy.arange(1,15)
>>> a
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> b = as_strided(a, (11,4), a.strides*2)
>>> b
array([[ 1, 2, 3, 4],
[ 2, 3, 4, 5],
[ 3, 4, 5, 6],
[ 4, 5, 6, 7],
[ 5, 6, 7, 8],
[ 6, 7, 8, 9],
[ 7, 8, 9, 10],
[ 8, 9, 10, 11],
[ 9, 10, 11, 12],
[10, 11, 12, 13],
[11, 12, 13, 14]])
请注意,数组b
中的值是a
中的值,只是以不同的方式查看。如果您打算修改.copy()
,请b
。
我在SciPy会议上看到了这一点。以下是slides的更多解释。
答案 1 :(得分:14)
最快的方式似乎是预分配数组,在答案的最底部作为选项7给出。
>>> import numpy as np
>>> A=np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14])
>>> A
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> np.array(zip(A,A[1:],A[2:],A[3:]))
array([[ 1, 2, 3, 4],
[ 2, 3, 4, 5],
[ 3, 4, 5, 6],
[ 4, 5, 6, 7],
[ 5, 6, 7, 8],
[ 6, 7, 8, 9],
[ 7, 8, 9, 10],
[ 8, 9, 10, 11],
[ 9, 10, 11, 12],
[10, 11, 12, 13],
[11, 12, 13, 14]])
>>>
您可以轻松地对此进行调整以适应变量块大小。
>>> n=5
>>> np.array(zip(*(A[i:] for i in range(n))))
array([[ 1, 2, 3, 4, 5],
[ 2, 3, 4, 5, 6],
[ 3, 4, 5, 6, 7],
[ 4, 5, 6, 7, 8],
[ 5, 6, 7, 8, 9],
[ 6, 7, 8, 9, 10],
[ 7, 8, 9, 10, 11],
[ 8, 9, 10, 11, 12],
[ 9, 10, 11, 12, 13],
[10, 11, 12, 13, 14]])
您可能希望比较它与使用itertools.islice
之间的效果。
>>> from itertools import islice
>>> n=4
>>> np.array(zip(*[islice(A,i,None) for i in range(n)]))
array([[ 1, 2, 3, 4],
[ 2, 3, 4, 5],
[ 3, 4, 5, 6],
[ 4, 5, 6, 7],
[ 5, 6, 7, 8],
[ 6, 7, 8, 9],
[ 7, 8, 9, 10],
[ 8, 9, 10, 11],
[ 9, 10, 11, 12],
[10, 11, 12, 13],
[11, 12, 13, 14]])
1. timeit np.array(zip(A,A[1:],A[2:],A[3:]))
10000 loops, best of 3: 92.9 us per loop
2. timeit np.array(zip(*(A[i:] for i in range(4))))
10000 loops, best of 3: 101 us per loop
3. timeit np.array(zip(*[islice(A,i,None) for i in range(4)]))
10000 loops, best of 3: 101 us per loop
4. timeit numpy.array([ A[i:i+4] for i in range(len(A)-3) ])
10000 loops, best of 3: 37.8 us per loop
5. timeit numpy.array(list(chunks(A, 4)))
10000 loops, best of 3: 43.2 us per loop
6. timeit numpy.array(byN(A, 4))
10000 loops, best of 3: 100 us per loop
# Does preallocation of the array help? (11 is from len(A)+1-4)
7. timeit B=np.zeros(shape=(11, 4),dtype=np.int32)
100000 loops, best of 3: 2.19 us per loop
timeit for i in range(4):B[:,i]=A[i:11+i]
10000 loops, best of 3: 20.9 us per loop
total 23.1us per loop
当len(A)增加(20000)时,4和5收敛到等效速度(44 ms)。 1,2,3和6都保持慢约3倍(135毫秒)。 7更快(1.36毫秒)。
答案 2 :(得分:4)
快速和肮脏的解决方案:
>>> a = numpy.arange(1,15)
>>> numpy.array([ a[i:i+4] for i in range(len(a)-3) ])
array([[ 1, 2, 3, 4],
[ 2, 3, 4, 5],
[ 3, 4, 5, 6],
[ 4, 5, 6, 7],
[ 5, 6, 7, 8],
[ 6, 7, 8, 9],
[ 7, 8, 9, 10],
[ 8, 9, 10, 11],
[ 9, 10, 11, 12],
[10, 11, 12, 13],
[11, 12, 13, 14]])
答案 3 :(得分:1)
使用itertools,并假设使用Python 2.6:
import itertools
def byN(iterable, N):
itrs = itertools.tee(iter(iterable), N)
for n in range(N):
for i in range(n):
next(itrs[n], None)
return zip(*itrs)
aby4 = numpy.array(byN(thearray, 4))
答案 4 :(得分:1)
广播!
from numpy import ogrid
def stretch(N=5,M=15):
x, y = ogrid[0:M,0:N]
return x+y+1
请注意,ogrid确实提供了以下内容:
>> ogrid[0:5,0:5]
>>
[array([[0],
[1],
[2],
[3],
[4]]),
array([[0, 1, 2, 3, 4]])]
让我们与这里给出的另一个解决方案进行比较:
def zipping(N=5,M=15):
A = numpy.arange(1, M+1)
return numpy.array(zip(*(A[i:] for i in range(N))))
比较(python 2.6,32位,1Go RAM)给出
>>> %timeit stretch(5,15)
10000 loops, best of 3: 61.2 us per loop
>>> %timeit zipping(5,15)
10000 loops, best of 3: 72.5 us per loop
>>> %timeit stretch(5,1e3)
10000 loops, best of 3: 128 us per loop
>>> %timeit zipping(5,1e3)
100 loops, best of 3: 4.25 ms per loop
40倍的加速速度有点适合缩放。
答案 5 :(得分:0)
我知道没有Python stdlib功能可以做到这一点。这很容易做到。这是一个基本上做它的生成器:
def chunks(sequence, length):
for index in xrange(0, len(sequence) - length + 1):
yield sequence[index:index + length]
您可以像这样使用
>>> import numpy
>>> a = numpy.arange(1, 15)
>>> a
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> numpy.array(list(chunks(a, 4)))
array([[ 1, 2, 3, 4],
[ 2, 3, 4, 5],
[ 3, 4, 5, 6],
[ 4, 5, 6, 7],
[ 5, 6, 7, 8],
[ 6, 7, 8, 9],
[ 7, 8, 9, 10],
[ 8, 9, 10, 11],
[ 9, 10, 11, 12],
[10, 11, 12, 13],
[11, 12, 13, 14]])
关于此代码的唯一奇怪之处是我在list
的结果上调用了chunks(a, 4)
。这是因为numpy.array
不接受任意迭代,例如生成器chunks
返回。如果你只是想迭代这些块,你不需要打扰。如果你真的需要将结果放入数组中,你可以这样做或者更有效的方式。
答案 6 :(得分:0)
有效的NumPy方法是here,这在这里重现有点太长了。它归结为使用一些步幅技巧,并且比用于大窗口尺寸的itertools快得多。例如,使用与Alex Martelli的方法基本相同的方法:
In [16]: def windowed(sequence, length):
seqs = tee(sequence, length)
[ seq.next() for i, seq in enumerate(seqs) for j in xrange(i) ]
return zip(*seqs)
我们得到:
In [19]: data = numpy.random.randint(0, 2, 1000000)
In [20]: %timeit windowed(data, 2)
100000 loops, best of 3: 6.62 us per loop
In [21]: %timeit windowed(data, 10)
10000 loops, best of 3: 29.3 us per loop
In [22]: %timeit windowed(data, 100)
1000 loops, best of 3: 1.41 ms per loop
In [23]: %timeit segment_axis(data, 2, 1)
10000 loops, best of 3: 30.1 us per loop
In [24]: %timeit segment_axis(data, 10, 9)
10000 loops, best of 3: 30.2 us per loop
In [25]: %timeit segment_axis(data, 100, 99)
10000 loops, best of 3: 30.5 us per loop