Python:添加包含列元素的成对产品的列的最快方法

时间:2017-09-14 13:22:26

标签: python arrays numpy matrix linear-algebra

假设我有一个numpy数组

X = np.array([[1,2,3],
              [4,5,6],
              [7,8,9]])

我想通过添加(在左侧)通过将所有可能的列对相乘得到的列来扩展此矩阵。在这个例子中,它将成为

X = np.array([[1, 2, 3, 2, 6],
              [4,5,6,20,24,30],
              [7,8,9,56,63,72]])

如果第四列是X[:,0]X[:,1]的乘积,则第五列是X[:,0]X[:,2]的乘积,第六列是X[:,1]的乘积{1}}和X[:,2]

我的尝试

我想使用np.hstack。但是我也知道使用循环减慢了一切,但我不知道如何在没有循环的情况下正确地完成它。

for i in range(matrix.shape[1]-1):
    for j in range(matrix.shape[1])[i:]:
        matrix2 = np.hstack((matrix, (matrix[:,i]*matrix[:,j]).reshape(-1,1))).copy()

问题在于它很慢而且我必须使用不同的矩阵,否则它会继续添加列...更好的主意吗?

1 个答案:

答案 0 :(得分:3)

方法#1

使用np.triu_indices获取成对列列索引。使用它们来选择从列索引到输入数组中获得的两组块。使用这些块执行逐元素乘法,最后将这些块作为新列与np.concatenate的输入数组一起堆叠。

因此,实施 -

n = X.shape[1]
r,c = np.triu_indices(n,1)
out0 = X[:,r] * X[:,c]
out = np.concatenate(( X, out0), axis=1)

方法#2

为了提高内存效率,从而提高性能,特别是对于大型数组,还有一个受this post启发,通过循环遍历配对 -

m,n = X.shape
N = n*(n-1)//2
idx = np.concatenate(( [0], np.arange(n-1,0,-1).cumsum() ))+n
start, stop = idx[:-1], idx[1:]
out = np.empty((m,n+N),dtype=X.dtype)
out[:,:n] = X
for j,i in enumerate(range(n-1)):
    out[:, start[j]:stop[j]] = X[:,i,None]*X[:,i+1:]

运行时测试

In [403]: X = np.random.randint(0,9,(10,100))

In [404]: %timeit app1(X)
     ...: %timeit app2(X)
     ...: 
1000 loops, best of 3: 277 µs per loop
1000 loops, best of 3: 350 µs per loop

In [405]: X = np.random.randint(0,9,(10,1000))

In [406]: %timeit app1(X)
     ...: %timeit app2(X)
     ...: 
10 loops, best of 3: 68.6 ms per loop
100 loops, best of 3: 12.5 ms per loop

In [407]: X = np.random.randint(0,9,(10,2000))

In [408]: %timeit app1(X)
     ...: %timeit app2(X)
     ...: 
1 loop, best of 3: 311 ms per loop
10 loops, best of 3: 44.8 ms per loop