创建Numpy数组而不枚举数组

时间:2016-08-18 17:35:20

标签: python arrays numpy

从这开始:

x = range(30,60,2)[::-1];
x = np.asarray(x); x

array([58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30])

创建一个这样的数组:(注意,第一项重复)但是如果我能在没有第一项重复的情况下更快地得到这个,我可以np.hstack第一项。

[[58 58 56 54 52]
 [56 56 54 52 50]
 [54 54 52 50 48]
 [52 52 50 48 46]
 [50 50 48 46 44]
 [48 48 46 44 42]
 [46 46 44 42 40]
 [44 44 42 40 38]
 [42 42 40 38 36]
 [40 40 38 36 34]
 [38 38 36 34 32]
 [36 36 34 32 30]
 [34 34 32 30 None]
 [32 32 30 None None]
 [30 30 None None None]]

下面的代码有效,希望它更快,而不是'循环和枚举。

arr = np.empty((0,5), int)

for i,e in enumerate(x):
    arr2 = np.hstack((x[i], x[i:i+4], np.asarray([None]*5)))[:5]
    arr  = np.vstack((arr,arr2))

4 个答案:

答案 0 :(得分:5)

方法#1

这是使用NumPy broadcasting -

的矢量化方法
N = 4 # width factor
x_ext = np.concatenate((x,[None]*(N-1)))
arr2D = x_ext[np.arange(N) + np.arange(x_ext.size-N+1)[:,None]]
out = np.column_stack((x,arr2D))

方法#2

这是另一个使用hankel -

的人
from scipy.linalg import hankel

N = 4 # width factor
x_ext = np.concatenate((x,[None]*(N-1)))
out = np.column_stack((x,hankel(x_ext[:4], x_ext[3:]).T))

运行时测试

这里是@Aaron's benchmarking script的修改版本,使用此帖子的输入格式与该脚本中用于公开基准测试的帖子相同,并且只关注这两种方法 -

upper_limit = 58 # We will edit this to vary the dataset sizes

print "Timings are : "
t = time()
for _ in range(1000):  #1000 iterations of @Aaron's soln.
    width = 3
    x = np.array(range(upper_limit,28,-2) + [float('nan')]*width)
    arr = np.empty([len(x)-width, width+2])
    arr[:,0] = x[:len(x)-width]
    for i in xrange(len(x)-width): 
        arr[i,1:] = x[i:i+width+1]
print(time()-t)

t = time()
for _ in range(1000): 
    N = 4 # width factor
    x_ext = np.array(range(upper_limit,28,-2) + [float('nan')]*(N-1))
    arr2D = x_ext[np.arange(N) + np.arange(x_ext.size-N+1)[:,None]]
    out = np.column_stack((x_ext[:len(x_ext)-N+1],arr2D))
print(time()-t)

案例#1(upper_limit = 58):

Timings are : 
0.0316879749298
0.0322730541229

案例#2(upper_limit = 1058):

Timings are : 
0.680443048477
0.124517917633

案例#3(upper_limit = 5058):

Timings are : 
3.28129291534
0.47504901886

答案 1 :(得分:3)

通过避免使用import numpy as np from time import time t = time() for _ in range(1000): #1000 iterations of my soln. width = 3 x = np.array(range(58,28,-2) + [float('nan')]*width) arr = np.empty([len(x)-width, width+2]) arr[:,0] = x[:len(x)-width] for i in xrange(len(x)-width): arr[i,1:] = x[i:i+width+1] print(time()-t) t = time() for _ in range(1000): #1000 iterations of OP code x = range(30,60,2)[::-1]; x = np.asarray(x) arr = np.empty((0,5), int) for i,e in enumerate(x): arr2 = np.hstack((x[i], x[i:i+4], np.asarray([None]*5)))[:5] arr = np.vstack((arr,arr2)) print(time()-t) t = time() for _ in range(1000): x = np.array(range(58,28,-2)) N = 4 # width factor x_ext = np.hstack((x,[None]*(N-1))) arr2D = x_ext[np.arange(N) + np.arange(x_ext.size-N+1)[:,None]] out = np.column_stack((x,arr2D)) print(time()-t) 并且只使用浮点数...来提高了一个数量级......

编辑:将@Divakar的帖子添加到计时...

>>> runfile('...temp.py', wdir='...')
0.0160000324249
0.374000072479
0.0319998264313
>>> 

打印出来:

{{1}}

答案 2 :(得分:3)

从Divaker的填充x

开始
N = 4 # width factor
x_ext = np.concatenate((x,[None]*(N-1)))

由于我们没有对它进行数学运算,因此使用None(生成对象数组)或np.nan(生成浮点数)填充应该没有太大区别。

可以通过对索引进行一点改动来消除列堆栈:

idx = np.r_[0,np.arange(N)] + np.arange(x_ext.size-N+1)[:,None]

这会产生

array([[ 0,  0,  1,  2,  3],
       [ 1,  1,  2,  3,  4],
       [ 2,  2,  3,  4,  5],
       [ 3,  3,  4,  5,  6],
       [ 4,  4,  5,  6,  7],
       ...

所以完整的结果是

x_ext[idx]

=====

另一种方法是使用跨步来创建一种滚动窗口。

as_strided = np.lib.stride_tricks.as_strided
arr2D = as_strided(x_ext, shape=(15,4), str‌​ides=(4,4))

这是as_strided更容易应用之一。 shape是直截了当的 - 所需结果的形状(没有重复列)(x.shape[0],N)

In [177]: x_ext.strides
Out[177]: (4,)

对于此类型的1d数组,下一项的步骤为4个字节。如果我使用3列将数组重新整形为2d,则下一行的步幅为12 - 3 * 4(3偏移)。

In [181]: x_ext.reshape(6,3).strides
Out[181]: (12, 4)

使用strides=(4,4)意味着到下一行的步骤只有4个字节,一个原始元素。

as_strided(x_ext,shape=(8,4),strides=(8,4))

产生2项重叠

array([[58, 56, 54, 52],
       [54, 52, 50, 48],
       [50, 48, 46, 44],
       [46, 44, 42, 40],
       ....

as_strided的潜在危险部分是可以创建一个对原始数据缓冲区之外的内存进行采样的数组。通常,它显示为大型随机数,此示例中出现None。如果您在使用数组指针和索引时不小心使用C代码,那就会遇到同样的错误。

as_strided数组是一个视图(不会复制重复的值)。因此写入该阵列可能很危险。带有column_stack的{​​{1}}会复制,根据需要复制重复的值。

答案 3 :(得分:2)

我建议构建一个具有相等列的初始矩阵,然后使用np.roll()来旋转它们:

import numpy as np
import timeit as ti
import numpy.matlib

x = range(30,60,2)[::-1];
x = np.asarray(x);

def sol1():
    # Your solution, for comparison
    arr = np.empty((0,5), int)

    for i,e in enumerate(x):
        arr2 = np.hstack((x[i], x[i:i+4], np.asarray([None]*5)))[:5]
        arr  = np.vstack((arr,arr2))
    return arr

def sol2():
    # My proposal
    x2 = np.hstack((x, [None]*3))
    mat = np.matlib.repmat(x2, 5, 1)
    for i in range(3):
        mat[i+2, :] = np.roll(mat[i+2, :], -(i+1))
    return mat[:,:-3].T


print(ti.timeit(sol1, number=100))
print(ti.timeit(sol2, number=100))

哪个guives:

0.026760146000015084
0.0038611710006080102

它使用for循环但它只在较短的轴上迭代。此外,将此代码用于其他配置而不是使用硬编码数字应该不难。