2015-05-04 148 views
2

我在numpy(Python 2.7)中从1d数组构建2d数组。我正在寻找最有效的方式来做到这一点。到目前为止,我想出了:Numpy - 从1d数组中有效地构建2d数组

a=np.ones(100000) 

# SUBSCRIPTING 

n_dim=3 
x=0 

for i in xrange(0,1000): 
    x=np.zeros(shape=(100000,n_dim)) 
    for j in xrange(0,n_dim): 
     x[:,j]=a*j 

# ~1.574 s/1000 loops - joinind 3 1d arrays 
# ~9.162 s/1000 loops - joinind 10 1d arrays 



# STACKING 

for i in xrange(0,1000): 
    x=a*0. 
    for j in xrange(1,n_dim): 
     x=np.vstack((x,a*j)) 
    x=x.T 

# ~1.786 s/1000 loops - joinind 3 1d arrays 
# ~16.603 s/1000 loops - joinind 10 1d arrays 

第一种方法(下标)是我想出了最快,在第二个方法(堆积)的性能提升与成长一维数组我加入的数量。由于我需要重复这一步很多,我想知道是否有更快的东西?如果能够提供显着的性能提升,我愿意采用那种失去清晰度的解决方案。

也许我可以尝试以限制堆叠操作数量的方式堆叠数组(例如,连接4个1d数组:第一个堆栈数组1和2,然后是数组3和4,以及最终得到的数组)。

我的问题是关于从1d阵列有效地构建2d数组。我在这里使用的数组中的值是虚拟的。在实际应用中,我加入的1d阵列中的大部分值可能会有所不同。

+0

你能提供一个较小输入的例子吗? –

+0

是关于一般堆叠还是关于您显示的计算? – plonser

回答

2

由于numpy存储(默认情况下)row-major order中的数组,因此按行设置值效率更高。因此,我会用:

x=np.zeros(shape=(n_dim, 100000)) 
for j in range(0,n_dim): 
    x[j,:]=a*j 

或者,您也可以定义x是列为主,然后,这是一样快,以前的代码:

x=np.zeros(shape=(100000,n_dim), order='F') 
for j in range(0,n_dim): 
    x[:,j]=a*j 

你也能创造出x numpy外部产品:

v = np.arange(n_dim) 
x = np.outer(v, a) 
+0

将x = np.zeros(shape =(100000,n_dim))更改为 x = np.zeros(shape =(100000,n_dim),order ='F')显着提高了速度。 1000个环路的三维尺寸为1.344秒,10个尺寸的环路尺寸为4.672秒。谢谢。外部产品不是我的选择,因为在实际情况下,合并的1d阵列中的所有条目都会有所不同。 – jakub

1

这是穷人的使用方式vstack;您将反复调用它,每个j

x=a*0. 
for j in xrange(1,n_dim): 
    x=np.vstack((x,a*j)) 
x=x.T 

正确的方法是构建阵列的列表,并使用vstack只有一次创建一个新的x

xlist=[] 
for j in xrange(1,n_dim): 
    xlist.append(a*j) 
x = np.array(xlist).T 

在此背景下append的作品一样好vstack,并可能会更快。还有一个column_stack函数。关键区别在于我利用快速列表追加以及array(和vstack)在其参数列表中占用很多项目的能力。

它甚至更好,如果你能在一个预分配阵列编写循环作为一个列表理解

x = np.array([a*j for j in xrange(1,n_dim)]) 

插入往往是最快的选择。但是您应该熟悉这种从列表构建方法。

基本np.array表达

np.array([[1,2,3],[4,5,6]]) 

只是此,建设从一维阵列的列表(或在这种情况下,列表)2d上。

np.array([a*0,a*1,a*2]) 

jakub指出,np.array是缓慢的。对于n_dim=10

In [257]: timeit x=np.array([(a*j) for j in range(n_dim)]).T 
1 loops, best of 3: 228 ms per loop 

In [258]: timeit x=np.array([(a*j).tolist() for j in range(n_dim)]).T 
1 loops, best of 3: 228 ms per loop 

显然np.array被转换输入阵列列表,然后做从嵌套列表(或东西等效)其通常的结构。

In [259]: timeit x=np.vstack([(a*j) for j in range(n_dim)]).T 
10 loops, best of 3: 24.9 ms per loop 

vstack在数组列表上的速度相当快。比迭代vstack(我预期的)更快。基本上一样Ramon's插入行(和插入order='F'

In [272]: %%timeit 
x=np.zeros((n_dim,a.shape[0])) 
for j in range(n_dim): 
    x[j,:]=a*j 
    .....: x=x.T 
    .....: 
10 loops, best of 3: 23.3 ms per loop 

虽然concatenate(由vstack使用)被编译,我怀疑它类似于多次插入一些东西。源C代码中通常会创建一个空目标数组,然后用适当的值填充它。

+0

我试过你的解决方案。它在3个维度上运行大约29 s/1000个循环。 10个尺寸是96.638s/1000圈。所以它可能是优雅的,但它似乎非常低效。 – jakub

+0

我做了一些时间。在这种情况下(加入数组),'np.array'做得不好。但是整个列表中的'vstack'确实很好。 – hpaulj

+0

我也在类似的设置中进行了计时,并且按照您的说法,这是拉蒙提出的第二好插入方案。时间仅供参考,10个维度:5.5s/1000个循环,3个维度:1.4s/1000个循环。我不知道如何改变顺序为'F'影响我的后续计算。我将检查这两种方法中的哪一种(Raymon的插入和你的vstack)为整个应用带来最大的性能增益。 – jakub