Dontwastetime
Dontwastetime

Reputation: 5

How to create a Numpy Matrix with a for loop?

I am trying to construct a matrix with numpy using an array of random numbers called noise with 4 values which should be multiplied with 8 different numbers from an array called "factor" resulting in 8 rows in the final matrix.

So the matrix should have 4 columns for each value in "noise" and 8 rows for each factor. I don't know how to achieve that.

This is the code I got so for:

import numpy as np  
from numpy import random

n = 4
noise = np.random.normal(size=n)


matrix = np.zeros((8,n)) # Pre-allocate matrix
for i in range(1,8):
   matrix[:,i] = [[noise]*i]


print(matrix)

I get the error message:


ValueError: setting an array element with a sequence.

Upvotes: 0

Views: 525

Answers (3)

Paul Panzer
Paul Panzer

Reputation: 53029

What you are trying to construct is the outer product

n = 4
noise = np.random.normal(size=n)
noise
# array([ 2.39723122, -0.99797246, -0.14242618, -0.55921136])

m = 8
factor = np.random.randint(0,10,m)
factor
# array([0, 5, 7, 6, 7, 3, 8, 6])

np.outer(factor,noise)
# array([[ 0.        , -0.        , -0.        , -0.        ],
#        [11.98615612, -4.98986228, -0.71213089, -2.79605682],
#        [16.78061856, -6.98580719, -0.99698324, -3.91447955],
#        [14.38338734, -5.98783473, -0.85455707, -3.35526818],
#        [16.78061856, -6.98580719, -0.99698324, -3.91447955],
#        [ 7.19169367, -2.99391737, -0.42727853, -1.67763409],
#        [19.17784979, -7.98377964, -1.13940942, -4.47369091],
#        [14.38338734, -5.98783473, -0.85455707, -3.35526818]])

The "outer" operation exists for many binary ufuncs. Because outer multiplication

np.multiply.outer(factor,noise)

is so common it has its own function outer.

The outer operation (for multiplication or other ufuncs) is (for 1D operands) roughly equivalent to

np.multiply(*np.ix_(factor,noise))

If a reducing form (prod for multiply, sum for add, min for minimum, etc.) exists we can also write

np.prod(np.ix_(factor,noise))

Finally, (somewhat unrelated) in case of the product we can also use einsum:

np.einsum('i,j',factor,noise)

Though einsum is maybe overkill for this problem.

Upvotes: 2

hpaulj
hpaulj

Reputation: 231335

In [12]: n = 4 
    ...: noise = np.random.normal(size=n)                                                                    
In [13]: noise                                                                                               
Out[13]: array([-1.93374989, -1.16536624,  0.42338714, -2.39942219])

Let's look at what you are trying to assign - for specific i:

In [14]: np.array([[noise]*1])                                                                               
Out[14]: array([[[-1.93374989, -1.16536624,  0.42338714, -2.39942219]]])
In [15]: np.array([[noise]*2])                                                                               
Out[15]: 
array([[[-1.93374989, -1.16536624,  0.42338714, -2.39942219],
        [-1.93374989, -1.16536624,  0.42338714, -2.39942219]]])
In [16]: np.array([[noise]*3])                                                                               
Out[16]: 
array([[[-1.93374989, -1.16536624,  0.42338714, -2.39942219],
        [-1.93374989, -1.16536624,  0.42338714, -2.39942219],
        [-1.93374989, -1.16536624,  0.42338714, -2.39942219]]])

You are applying the *3 to a list - which means 'replicate':

In [17]: [[noise]*3]                                                                                         
Out[17]: 
[[array([-1.93374989, -1.16536624,  0.42338714, -2.39942219]),
  array([-1.93374989, -1.16536624,  0.42338714, -2.39942219]),
  array([-1.93374989, -1.16536624,  0.42338714, -2.39942219])]]

The shapes are (1,1,4), (1,2,4), (1,3,4) etc. Brackets in Python create a list; don't use them casually. But

In [21]: np.zeros((8,4))[:,1].shape                                                                          
Out[21]: (8,)

you are trying to put each in a size (8,) slot.

Did you instead want to multiply the values of noise by i?

matrix = np.zeros((8,n)) # Pre-allocate matrix
for i in range(8):
   matrix[i,:] = noise*i

should work, properly matching the matrix[i,:] slot with the source, noise.

Upvotes: 0

GZ0
GZ0

Reputation: 4263

You can just do this instead of using a loop:

matrix = np.random.normal(size=(1, n)) * np.arange(8).reshape(-1, 1)

Here, the left hand-side of the multiplication has the shape (1, n) while the right-hand side has the shape (8, 1). So both of them will be broadcasted to the shape (8, n) and then an element-wise multiplication is performed.

Upvotes: 1

Related Questions