1

I have this big serie of length t (t = 200K rows)

prices = [200, 100, 500, 300 ..]

and I want to calculate a matrix (tXt) where a value is calculated as:

matrix[i][j] = prices[j]/prices[i] - 1

I tried this using a double for, but it's too slow. Any ideas how to perform it better?

for p0 in prices:
    for p1 in prices:
        matrix[i][j] = p1/p0 - 1
sparkle
  • 7,530
  • 22
  • 69
  • 131
  • https://stackoverflow.com/questions/11144513/numpy-cartesian-product-of-x-and-y-array-points-into-single-array-of-2d-points – Mortz Dec 28 '18 at 08:59

3 Answers3

2

A vectorized solution is using np.meshgrid, with prices and 1/prices as arguments (note that prices must be an array), and multiplying the result and substracting 1 in order to compute matrix[i][j] = prices[j]/prices[i] - 1:

a, b = np.meshgrid(p, 1/p)
a * b - 1

As an example:

p = np.array([1,4,2])

Would give:

a, b = np.meshgrid(p, 1/p)
a * b - 1

array([[ 0.  ,  3.  ,  1.  ],
       [-0.75,  0.  , -0.5 ],
       [-0.5 ,  1.  ,  0.  ]])

Quick check of some of the cells:

(i,j)    prices[j]/prices[i] - 1
--------------------------------
(1,1)        1/1 - 1 = 0
(1,2)        4/1 - 1 = 3
(1,3)        2/1 - 1 = 1
(2,1)        1/4 - 1 = -0.75

Another solution:

[p] / np.array([p]).T - 1

array([[ 0.  ,  3.  ,  1.  ],
       [-0.75,  0.  , -0.5 ],
       [-0.5 ,  1.  ,  0.  ]])
yatu
  • 86,083
  • 12
  • 84
  • 139
1

I guess it can be done in this way

import numpy

prices = [200., 300., 100., 500., 600.]
x = numpy.array(prices).reshape(1, len(prices))
matrix = (1/x.T) * x - 1

Let me explain in details. This matrix is a matrix product of column vector of element-wise reciprocal price values and a row vector of original price values. Then matrix of ones of the same size needs to be subtracted from the result. First of all we create row-vector from prices list

x = numpy.array(prices).reshape(1, len(prices))

Reshaping is required here. Otherwise your vector will have shape (len(prices),), not required (1, len(prices)). Then we compute a column vector of element-wise reciprocal price values:

(1/x.T)

Finally, we compute the resulting matrix

matrix = (1/x.T) * x - 1

Here ending - 1 will be broadcasted to a matrix of the same shape with (1/x.T) * x.

VirtualVDX
  • 2,231
  • 1
  • 13
  • 14
1

There are two idiomatic ways of doing an outer product-type operation. Either use the .outer method of universal functions, here np.divide:

In [2]: p = np.array([10, 20, 30, 40])

In [3]: np.divide.outer(p, p)
Out[3]: 
array([[ 1.        ,  0.5       ,  0.33333333,  0.25      ],
       [ 2.        ,  1.        ,  0.66666667,  0.5       ],
       [ 3.        ,  1.5       ,  1.        ,  0.75      ],
       [ 4.        ,  2.        ,  1.33333333,  1.        ]])

Alternatively, use broadcasting:

In [4]: p[:, None] / p[None, :]
Out[4]: 
array([[ 1.        ,  0.5       ,  0.33333333,  0.25      ],
       [ 2.        ,  1.        ,  0.66666667,  0.5       ],
       [ 3.        ,  1.5       ,  1.        ,  0.75      ],
       [ 4.        ,  2.        ,  1.33333333,  1.        ]])

This p[None, :] itself can be spelled as a reshape, p.reshape((1, len(p))), but readability.

Both are equivalent to a double for-loop:

In [6]: o = np.empty((len(p), len(p)))

In [7]: for i in range(len(p)):
   ...:     for j in range(len(p)):
   ...:         o[i, j] = p[i] / p[j]
   ...:         

In [8]: o
Out[8]: 
array([[ 1.        ,  0.5       ,  0.33333333,  0.25      ],
       [ 2.        ,  1.        ,  0.66666667,  0.5       ],
       [ 3.        ,  1.5       ,  1.        ,  0.75      ],
       [ 4.        ,  2.        ,  1.33333333,  1.        ]])
ev-br
  • 24,968
  • 9
  • 65
  • 78