setting an array element with a sequence error in python - python

I started studying python and I have a question for the program. I am writing
as the first step I thought of creating a big matrix and a big vectors where I will put some smaller vectors and smaller matrices. I created at random.
I have created a function that returns the max eigen values of those small matrices and save them in a vector. Also I created a function that basically does the multiplication of the transpose of my small vectors with the small matrices that I had randomly calculated. However when I try to pass the value of the multiplication, I get the following error
"setting an array element with a sequence."
import numpy as np
from scipy import linalg as lg
import math
N=5;
n=3;
Qs=np.zeros((n,N*n))
xs=np.zeros(n*N)
qs=np.zeros(n*N)
grads=np.zeros(N*n)
Lfi=np.zeros(N)
pis=np.zeros(N*n)
pi=np.zeros(N)
phat=np.zeros(N)
j=0;
gamma=np.zeros(N)
def gradient(Q,x) :
return x.transpose().dot(Q)
def eigen(Q):
val, vec = lg.eig(Q)
return np.amax(Q)
for i in range(0,N):
A = np.random.randint(10, size=(n,n))
Qs[0:n,j:j+n] += A
x = np.random.randint(10, size=(n))
qs[j:j+n] += x
x = np.random.randint(10, size=(n))
xs[j:j+n] += x
j = j+n
Lfi[i] = eigen(A)
grads[i] = gradient(A,x)
Why do I get the error for the gradient and not for example at the Lfi?

Your gradient function returns something else than what is expected by grads. From the error message I can tell that grads is numpy array which is not as forgiving as default python list. It has a type associated with it and it requires every element to be of that type.
e.g.
a = np.array([0] * 10)
print(type(a[0]))
this will tell you that the type of elements in this array is numpy.int64 (obviously there are many types and this is just a one of them). If you try to assign some value of a different type, python will try to coerce it to numpy.int64. But obviously, there is no sensible (general) way to coerce another array or matrix to a single number.
If you try
a[0] = [1, 2, 3]
then you will receive the error mentioned by you
ValueError: setting an array element with a sequence.
And why don't you receive the error when calling eigen function? Well, because it just returns a single value, not an array. np.amax(Q) returns a single value if you don't specify axis parameter which is set to None by default.

Related

Strange comportement of list/array

I want to understand why the comportement of my array is like that:
import numpy as np
import math
n=10
P=np.array([[0]*n]*n)
P[2][2]=1 #It works as I want
for i in range(n):
for j in range(n):
P[i][j]=math.comb(n,j+1)*((i+1)/n)**(j+1)*(1-(i+1)/n)**(n-j-1)
print(math.comb(n,j+1)*((i+1)/n)**(j+1)*(1-(i+1)/n)**(n-j-1))
print(P)
I get as a result for P an array with only 0 except 1 for the (n,n) position but values printed are not 0.
I suppose it comes from the fact that I use [[0]*n]*n for my list with mutable/immutable variable because it works well when I use np.zeros() but I don't understand why it works when I set value manually (with P[2][2]=1 for example)
Thanks
The way you are creating the array is defaulting to an integer dtype because it uses the first value to determine the type if you don't explicitly set it. You can demonstrate this by trying to assign a float instead of an int with
P[2][2]=1 #It works as I want
P[2][2]=0.3 #It doesn't work
To use your approach you need to create an array with a dtype of float so values don't get clipped: P=np.array([[0.0]*n]*n) or P=np.array([[0]*n]*n, dtype=float).
This will produce an array of the expected values:
array([[3.87420489e-01, 1.93710245e-01, 5.73956280e-02, 1.11602610e-02,
1.48803480e-03, 1.37781000e-04, 8.74800000e-06, 3.64500000e-07,
9.00000000e-09, 1.00000000e-10],
[2.68435456e-01, 3.01989888e-01, 2.01326592e-01, 8.80803840e-02,
2.64241152e-02, 5.50502400e-03, 7.86432000e-04, 7.37280000e-05,
4.09600000e-06, 1.02400000e-07],
...

How can I scale (x-axes) and shift data within array in Python?

I have an array of data that represents some signal f(x). If there is a way to perform operations which gives me in result an array of f(ax + b) by using only first array?
For "+ b" shifting part I use numpy.insert to insert array of zeros to shift signal left or right, but can't figure how to do f(ax). Please keep in mind that I do not want to a*f(x) and simple multiplication of array by constant is not an option.
Edit: Unfortunately I have no access to function that generated first array, I think that resampling functions are the ones that will solve rescalling issue.
Depending on the size of the array there are several solutions, the simplest is to access the array f as f[a*x+b] and checking if that is a valid index. Here is a code that creates the shifted array:
import numpy as np
def scale_shift(f, a , b):
i = np.arange(len(f))*a+b
y = f[i[(0<=i) & (i<len(f))]]
return y
n = 10
f = np.random.rand(n)
print(scale_shift(f,2,1))
Note that the length of the new array will depend on the shift. You can use % if you want to wrap around the boundaries

Defining a matrix with unknown size in python

I want to use a matrix in my Python code but I don't know the exact size of my matrix to define it.
For other matrices, I have used np.zeros(a), where a is known.
What should I do to define a matrix with unknown size?
In this case, maybe an approach is to use a python list and append to it, up until it has the desired size, then cast it to a np array
pseudocode:
matrix = []
while matrix not full:
matrix.append(elt)
matrix = np.array(matrix)
You could write a function that tries to modify the np.array, and expand if it encounters an IndexError:
x = np.random.normal(size=(2,2))
r,c = (5,10)
try:
x[r,c] = val
except IndexError:
r0,c0 = x.shape
r_ = r+1-r0
c_ = c+1-c0
if r > 0:
x = np.concatenate([x,np.zeros((r_,x.shape[1]))], axis = 0)
if c > 0:
x = np.concatenate([x,np.zeros((x.shape[0],c_))], axis = 1)
There are problems with this implementation though: First, it makes a copy of the array and returns a concatenation of it, which translates to a possible bottleneck if you use it many times. Second, the code I provided only works if you're modifying a single element. You could do it for slices, and it would take more effort to modify the code; or you can go the whole nine yards and create a new object inheriting np.array and override the .__getitem__ and .__setitem__ methods.
Or you could just use a huge matrix, or better yet, see if you can avoid having to work with matrices of unknown size.
If you have a python generator you can use np.fromiter:
def gen():
yield 1
yield 2
yield 3
In [11]: np.fromiter(gen(), dtype='int64')
Out[11]: array([1, 2, 3])
Beware if you pass an infinite iterator you will most likely crash python, so it's often a good idea to cap the length (with the count argument):
In [21]: from itertools import count # an infinite iterator
In [22]: np.fromiter(count(), dtype='int64', count=3)
Out[22]: array([0, 1, 2])
Best practice is usually to either pre-allocate (if you know the size) or build the array as a list first (using list.append). But lists don't build in 2d very well, which I assume you want since you specified a "matrix."
In that case, I'd suggest pre-allocating an oversize scipy.sparse matrix. These can be defined to have a size much larger than your memory, and lil_matrix or dok_matrix can be built sequentially. Then you can pare it down once you enter all of your data.
from scipy.sparse import dok_matrix
dummy = dok_matrix((1000000, 1000000)) # as big as you think you might need
for i, j, data in generator():
dummy[i,j] = data
s = np.array(dummy.keys).max() + 1
M = dummy.tocoo[:s,:s] #or tocsr, tobsr, toarray . . .
This way you build your array as a Dictionary of Keys (dictionaries supporting dynamic assignment much better than ndarray does) , but still have a matrix-like output that can be (somewhat) efficiently used for math, even in a partially built state.

Trying to convert a MATLAB array to a Python array

I have this MATLAB code that I need to translate to python, however there is an issue in creating a new column in the firings array. In MATLAB, the code creates an n*2 matrix that is initially empty and I want to be able to do the same in python. Using NumPy, I created fired = np.where(v >= 30). However python creates a tuple rather than an array so it throws an error:
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
This is the code I have in MATLAB that I would like converted into Python
firings=[];
firings=[firings; t+0*fired, fired];
Help is appreciated! Thanks!
np.where generates a two-element tuple if the array is 1D in nature. For the 1D case, you would need to access the first element of the result of np.where only:
fired = np.where(v >= 30)[0]
You can then go ahead and concatenate the matrices. Also a suggestion provided by user #Divakar would be to use np.flatnonzero which would equivalently find the non-zero values in a NumPy array and flattened into a 1D array for less headaches:
fired = np.flatnonzero(v >= 30)
Take note that the logic to concatenate would not work if there were no matches found in fired. You will need to take this into account when you look at your concatenating logic. The convenient thing with MATLAB is that you're able to concatenate empty matrices and the result is no effect (obviously).
Also note that there is no conception of a row vector or column vector in NumPy. It is simply a 1D array. If you want to specifically force the array to be a column vector as you have it, you need to introduce a singleton axis in the second dimension for you to do this. Note that this only works provided that np.where gave you matched results. After, you can use np.vstack and np.hstack to vertically and horizontally concatenate arrays to help you do what you ask. What you have to do first is create a blank 2D array, then do what we just covered:
firings = np.array([[]]) # Create blank 2D array
# Some code here...
# ...
# ...
# fired = find(v >= 30); % From MATLAB
fired = np.where(v >= 30)[0]
# or you can use...
# fired = np.flatnonzero(v >= 30)
if np.size(fired) != 0:
fired = fired[:, None] # Introduce singleton axis
# Update firings with two column vectors
# firings = [firings; t + 0 * fired, fired]; % From MATLAB
firings = np.vstack([firings, np.hstack([t + 0*fired, fired])])
Here np.size finds the total number of elements in the NumPy array. If the result of np.where generated no results, the number of elements in fired should be 0. Therefore the if statement only executes if we have found at least one element in v subject to v >= 30.
If you use numpy, you can define an ndarray:
import numpy as np
firings=np.ndarray(shape=(1,2)
firings[0][0:]=(1.,2.)
firings=np.append(firings,[[3.,4.]],axis=0)

Importing just one value with numpy.genfromtxt

I would like to import just one value from a csv file. So far, I have been succesfull at using the skip_header and skip_footer options to seek out this element. It is a float value. One problem though, when I try to use this one element from my array, I get an error. Example:
import numpy as np
x = np.genfromtxt('junker.txt',skip_header=6,skip_footer=7)
print x
returns
array(10)
however
print x[0]
returns
TypeError: len() of unsized object
I just want to be able to use this value however I cannot because it's in a numpy array. Please help
a numpy array in that form is actually just a number. For example:
x = np.array([1])
Has a length of 1. However your array does not. Being just a number, you may utilize it right away! Example
x = np.array(3)
y = x + 3
print y
Will yield 3.
The length of x will yield an error because while this is an array, it is technically a zero dimensional array. Hence a length cannot be recovered from this variable.

Categories