简体   繁体   中英

Numpy - Matrix multiplication

I spent about 2 hours trying to figure out what's going on, but for the life of me I can't figure out why switching the order of matrices when multiplying doesn't seem to work:

Using Python 2.7x:

import numpy as np
num_segments = 25
num_vintages = 24
# Create a 3d matrix 25 deep x 24r x 24c
mx_loans_new_loans = np.zeros((num_segments, num_vintages, num_vintages))

# Create the multiplication vector - same as the first dimension of 3d matrix
mult_vector = np.arange(10,35)
len(mult_vector)

The intent is to fill in the matrix on the diagonal with the mult_vector . Here is the part I can't wrap my head around.

This version does not fulfill the intent:

for (i, x) in enumerate(mx_loans_new_loans):
    np.fill_diagonal(x, 1)
    x = x * mult_vector[i]

The results still spit out just the original matrix with 1's on the diagonal.

This version, however, does work. All I've done is reverse the matrices in the enumerate :

for (i, x) in enumerate(mult_vector):
    np.fill_diagonal(mx_loans_new_loans[i], 1)
    mx_loans_new_loans[i] = mx_loans_new_loans[i] * x

Sidenote: I've since realized a more optimized version fills the intent:

for (i, x) in enumerate(mx_loans_new_loans):
    np.fill_diagonal(x, mult_vector[i])

But does anyone know why the first version doesn't work, but the second version does? What am I missing? Is this a broadcasting problem or something simpler?

mx_loans_new_loans is 3d, (25,24,24). x in the loop is (24,24). multi_vector is (25,); multivector[i] a scalar.

The fill_diagonal sets the 1s in x (in place). But x = x * mult_vector[i] , replaces x with a new array, and doesn't change the original. That is, it reassigns variable x .

x *= mult_vector[i]

should change the diagonals in the original array.

mx_loans_new_loans[i] = ... changes this subarray in place. Again mx_loans_new_loans[i] *= ... should work as well.

With zip we can iterate on both arrays:

In [44]: Z=np.zeros((4,3,3),int)
In [45]: for i,j in zip(Z,np.arange(10,14)):
    ...:     np.fill_diagonal(i,j)
    ...:     
In [46]: Z
Out[46]: 
array([[[10,  0,  0],
        [ 0, 10,  0],
        [ 0,  0, 10]],

       [[11,  0,  0],
        [ 0, 11,  0],
        [ 0,  0, 11]],

       [[12,  0,  0],
        [ 0, 12,  0],
        [ 0,  0, 12]],

       [[13,  0,  0],
        [ 0, 13,  0],
        [ 0,  0, 13]]])

We can view all the diagonals as set in the loop with:

In [47]: Z[:,np.arange(3),np.arange(3)]
Out[47]: 
array([[10, 10, 10],
       [11, 11, 11],
       [12, 12, 12],
       [13, 13, 13]])

And modify them with (not quite right):

In [48]: Z[:,np.arange(3),np.arange(3)]=np.arange(20,23)
In [49]: Z
Out[49]: 
array([[[20,  0,  0],
        [ 0, 21,  0],
        [ 0,  0, 22]],

       [[20,  0,  0],
        [ 0, 21,  0],
        [ 0,  0, 22]],

       [[20,  0,  0],
        [ 0, 21,  0],
        [ 0,  0, 22]],

       [[20,  0,  0],
        [ 0, 21,  0],
        [ 0,  0, 22]]])

better:

In [50]: Z[:,np.arange(3),np.arange(3)]=np.arange(20,24)[:,None]
In [51]: Z
Out[51]: 
array([[[20,  0,  0],
        [ 0, 20,  0],
        [ 0,  0, 20]],

       [[21,  0,  0],
        [ 0, 21,  0],
        [ 0,  0, 21]],

       [[22,  0,  0],
        [ 0, 22,  0],
        [ 0,  0, 22]],

       [[23,  0,  0],
        [ 0, 23,  0],
        [ 0,  0, 23]]])

Another example of how assignment changes arrays (or not):

In [97]: x = np.zeros((2,3),int)

y is a view , a way of looking at one row of x :

In [99]: y = x[0]
In [100]: id(y)
Out[100]: 2877147400

In-place change to y appears as a change to x :

In [101]: y += 3
In [102]: y
Out[102]: array([3, 3, 3])
In [103]: x
Out[103]: 
array([[3, 3, 3],
       [0, 0, 0]])

But a y= change to y breaks the connection. y is no longer a view (row) of x , but rather a whole new array.

In [104]: y = y + 3
In [105]: y
Out[105]: array([6, 6, 6])
In [106]: x
Out[106]: 
array([[3, 3, 3],
       [0, 0, 0]])
In [107]: id(y)
Out[107]: 2876795264

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM