fastest way to create a matrix who cols are a product of each other

Viewed 50

Suppose I have a matrix X, with n columns. I want to create a new matrix, Y such that each column of Y is a product of two different columns of X.

Currently, I am doing a loop, something like this (not my actual code, but captures the essence of the code):

Y = np.array(X.shape[0], int(n * (n-1)/2))
cnt = 0
for j1 in range(0, n-1):
   for j2 in range(j1+1, n):         
      Y[:, cnt] = X[:, j1] * X[:, j2]
      cnt += 1

I was wondering if anyone knows if there is a faster way to generate (populate) matrix Y than the double loop that I am doing ? For instance, any function in numpy that be re-used to generate such a matrix quickly ?

2 Answers

Since you are looking for combinations of columns without repetition (i.e. col 0 * col 1 is the same as col 1 * col 0), I would use itertools since the combination is over something relatively smaller (the indices):

>>> x = np.arange(24).reshape(6,4)      
>>> list(combinations(range(x.shape[1]), 2))  # For illustrative purposes. We want all pairs of different columns.              
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]                          |
>>> np.vstack([x[:, i]*x[:, j] for i, j in combinations(range(x.shape[1]), 2)]).T                                             
array([[  0,   0,   0,   2,   3,   6],                         
       [ 20,  24,  28,  30,  35,  42],                         
       [ 72,  80,  88,  90,  99, 110],                         
       [156, 168, 180, 182, 195, 210],                         
       [272, 288, 304, 306, 323, 342],                         
       [420, 440, 460, 462, 483, 506]])                        
               

Using broadcasting (I think depending on your input might be faster):

Z = X.T[:,None]*X.T
output = Z[np.triu_indices(X.shape[1],k=1)].T

example input/output:

X = np.arange(24).reshape(6,4)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]

output:
[[  0   0   0   2   3   6]
 [ 20  24  28  30  35  42]
 [ 72  80  88  90  99 110]
 [156 168 180 182 195 210]
 [272 288 304 306 323 342]
 [420 440 460 462 483 506]]
Related