0

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.

1
  • So matrix is (8,n) and matrix[:,i] is (n,) shape. noise is (n,) shape. But what is the shape of [[noise]*i]. It's actually a list, but when turned into an array, what is it? Commented Aug 18, 2019 at 19:24

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

0
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.

2 Comments

Thanks a lot for your help. What can I do if the values of i are not in the range of (0,8) but come also from an array with random numbers. The following doesn't work: python noise_fac = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]) b = 0.66 noise = rice.rvs(b, size=n) matrix = np.zeros((8,n)) # Pre-allocate matrix for i in (noise_fac): matrix[i,:] = noise*i print(matrix)
It''s not easy to read code in a comment. Can't you index noise_fac like you do matrix? Or adapt @GZ0's answer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.