scipy.sparse for numpy.random_multivariate_normal - python

I wanted to save a bit of memory, and thought I'd create a scipy.sparse identity matrix (dim is in the thousands, not terrible, but also not frugal). Notice its shape passes the assert:
cov = sigma_0 * sparse.identity(dim, dtype=np.float32)
assert (dim, dim) == cov.shape
result = np.random.multivariate_normal(mu, cov)
E ValueError: cov must be 2 dimensional and square
The following, however, works fine:
cov = sigma_0 * np.identity(dim, dtype=np.float32)
assert (dim, dim) == cov.shape
result = np.random.multivariate_normal(mu, cov)
Did I miss it, somewhere, in the docs to say that sparse covariance matrices are expected fail with a ValueError?

What's happening here is that in np.random.multivariate_normal the input array is cast to an array:
cov = np.array(cov)
which ends up creating a scalar array of dtype object since numpy doesn't know anything about sparse matrices.
In [3]: cov = sparse.identity(100, dtype=np.float32)
In [4]: cov.shape
Out[4]: (100, 100)
In [5]: np.array(cov)
Out[5]:
array(<100x100 sparse matrix of type '<type 'numpy.float32'>'
with 100 stored elements (1 diagonals) in DIAgonal format>, dtype=object)

Related

Writing a Transpose a vector in python

I have to write a python function where i need to compute the vector
For A is n by n and xn is n by 1
r_n = Axn - (xn^TAxn)xn
Im using numpy but .T doesn't work on vectors and when I just do
r_n = A#xn - (xn#A#xn)#xn but xn#A#xn gives me a scaler.
I've tried changing the A with the xn but nothing seems to work.
Making a 3x1 numpy array like this...
import numpy as np
a = np.array([1, 2, 3])
...and then attempting to take its transpose like this...
a_transpose = a.T
...will, confusingly, return this:
# [1 2 3]
If you want to define a (column) vector whose transpose you can meaningfully take, and get a row vector in return, you need to define it like this:
a = np.reshape(np.array([1, 2, 3]), (3, 1))
print(a)
# [[1]
# [2]
# [3]]
a_transpose = a.T
print(a_transpose)
# [[1 2 3]]
If you want to define a 1 x n array whose transpose you can take to get an n x 1 array, you can do it like this:
a = np.array([[1, 2, 3]])
and then get its transpose by calling a.T.
If A is (n,n) and xn is (n,1):
A#xn - (xn#A#xn)#xn
(n,n)#(n,1) - ((n,1)#(n,n)#(n,1)) # (n,1)
(n,1) error (1 does not match n)
If xn#A#xn gives scalar that's because xn is (n,) shape; as per np.matmul docs that's a 2d with two 1d arrays
(n,)#(n,n)#(n,) => (n,)#(n,) -> scalar
I think you want
(1,n) # (n,n) # (n,1) => (1,1)
Come to think of it that (1,1) array should be same single values as the scalar.
Sample calculation; 1st with the (n,) shape:
In [6]: A = np.arange(1,10).reshape(3,3); x = np.arange(1,4)
In [7]: A#x
Out[7]: array([14, 32, 50]) # (3,3)#(3,)=>(3,)
In [8]: x#A#x # scalar
Out[8]: 228
In [9]: (x#A#x)#x
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[9], line 1
----> 1 (x#A#x)#x
ValueError: matmul: Input operand 0 does not have enough dimensions (has 0, gufunc core with signature (n?,k),(k,m?)->(n?,m?) requires 1)
matmul does not like to work with scalars. But we can use np.dot instead, or simply multiply:
In [10]: (x#A#x)*x
Out[10]: array([228, 456, 684]) # (3,)
In [11]: A#x - (x#A#x)*x
Out[11]: array([-214, -424, -634])
Change the array to (3,1):
In [12]: xn = x[:,None]; xn.shape
Out[12]: (3, 1)
In [13]: A#xn - (xn.T#A#xn)*xn
Out[13]:
array([[-214],
[-424],
[-634]]) # same numbers but in (3,1) shape

Why doesn't np.square return ouput as expected?

I have a 2 dimensional numpy matrix whose type is numpy.ndarray of uint8.
Now when I perform np.square on the array, it does not return the expected result.
Here's an example of the code on the console and its output after I create the numpy array:
arr[0, 0] outputs 203
Now,
np.square(203) outputs 41209
But,
np.square(arr[0, 0]) outputs 249
This odd behavior was also observed for the np.sqrt method.
According to numpy.org np.uint8is Unsigned integer (0 to 255)
import numpy as np
arr = np.array([[203, 32, 45, 34], [34,322,780,54]])
arr1 = arr.astype('uint8')
arr2 = arr.astype('uint16')
sq = np.square(203)
sq8 = np.square(arr1[0,0])
sq16 = np.square(arr2[0,0])
sq, sq8, sq16, type(sq), type(sq8), type(sq16)
output:
(41209, 249, 41209, numpy.intc, numpy.uint8, numpy.uint16)
41209 is 249 in uint8:
num = np.array([41209])
num1 = arr.astype('uint8')
num1
>>> array([249], dtype=uint8)
np.square like other ufunc can return results with various dtypes. Looks like it 'prefers' to return a matching dtype:
In [109]: np.square(np.array([203], 'uint8'),dtype=int)
Out[109]: array([41209])
In [110]: np.square(np.array([203], 'uint8'),dtype='uint8')
Out[110]: array([249], dtype=uint8)
In [111]: np.square(np.array([203], 'uint8'))
Out[111]: array([249], dtype=uint8)
In [112]: np.square(np.array([203], 'uint8'),dtype='uint8')
Out[112]: array([249], dtype=uint8)
In [113]: np.square(np.array([203], 'uint8'),dtype='uint16')
Out[113]: array([41209], dtype=uint16)
In [114]: np.square(np.array([203], 'uint8'),dtype='int')
Out[114]: array([41209])
In [115]: np.square(np.array([203], 'uint8'),dtype='float')
Out[115]: array([41209.])
https://numpy.org/doc/stable/reference/ufuncs.html#casting-rules
and under signature parameter.
In [118]: np.square.types
Out[118]:
['b->b',
'B->B', # uint8
'h->h',
'H->H',
'i->i',
...]
There are more details in handling of casting and dtypes, but the basic point is that if using 'exotic' dtypes like unit8 beware of overflow etc. Even with 'int32' overflow can be problem, but at much larger numbers. A more common problem arise when doing some calculation on integers that results in floats.
A recent SO about dtypes with /= operator.
numpy.array's have bizarre behavior with /= operator?
Many times I've had to ask SO questions - what's the shape, what's the dtype. Those are fundamental properties of a numpy array. Getting those right is 80% of the debugging battle.

Averaging when iterating over numpy array

I have a dataset called MEL of shape (94824,) wherein most instances have shape (99, 13) but some have smaller shapes. It consists of (float) MEL frequencies. I'm trying to put all the values in an empty numpy matrix of shape (94824, 99 , 13). So some instances are left empty. Any suggestions?
MEL type = numpy.ndarray
for i in MEL type(i) = <class 'numpy.ndarray'>
for j in i type (j) = <class 'numpy.ndarray'>
Since your MEL array is not of homogeneous shape, first we need to filter out the arrays whose shape is common (i.e. (99, 13)). For this, we could use:
filtered = []
for arr in MEL:
if arr.shape == (99, 13):
filtered.append(arr)
else:
continue
Then we can initialize an array to hold the results. And then we can iterate over this filtered list of arrays and calculate the mean over axis 1 like:
averaged_arr = np.zeros((len(filtered), 99))
for idx, arr in enumerate(filtered):
averaged_arr[idx] = np.mean(arr, axis=1)
This should compute the desired matrix.
Here is a demo to reproduce your setup, assuming all arrays of the same shape:
# inputs
In [20]: MEL = np.empty(94824, dtype=np.object)
In [21]: for idx in range(94824):
...: MEL[idx] = np.random.randn(99, 13)
# shape of the array of arrays
In [13]: MEL.shape
Out[13]: (94824,)
# shape of each array
In [15]: MEL[0].shape
Out[15]: (99, 13)
# to hold results
In [17]: averaged_arr = np.zeros((94824, 99))
# compute average
In [18]: for idx, arr in enumerate(MEL):
...: averaged_arr[idx] = np.mean(arr, axis=1)
# check the shape of resultant array
In [19]: averaged_arr.shape
Out[19]: (94824, 99)

Vectorization and matrix multiplication by scalars

I am new to python/numpy.
I need to do the following calculation:
for an array of discrete times t, calculate $e^{At}$ for a $2\times 2$ matrix $A$
What I did:
def calculate(t_,x_0,v_0,omega_0,c):
# define A
a_11,a_12, a_21, a_22=0,1,-omega_0^2,-c
A =np.matrix([[a_11,a_12], [a_21, a_22]])
print A
# use vectorization
temps = np.array(t_)
A_ = np.array([A for k in range (1,n+1,1)])
temps*A_
x_=scipy.linalg.expm(temps*A)
v_=A*scipy.linalg.expm(temps*A)
return x_,v_
n=10
omega_0=1
c=1
x_0=1
v_0=1
t_ = [float(5*k*np.pi/n) for k in range (1,n+1,1)]
x_, v_ = calculate(t_,x_0,v_0,omega_0,c)
However, I get this error when multiplying A_ (array containing n times A ) and temps (containg the times for which I want to calculate exp(At) :
ValueError: operands could not be broadcast together with shapes (10,) (10,2,2)
As I understand vectorization, each element in A_ would be multiplied by element at the same index from temps; but I think i don't get it right.
Any help/ comments much appreciated
A pure numpy calculation of t_ is (creates an array instead of a list):
In [254]: t = 5*np.arange(1,n+1)*np.pi/n
In [255]: t
Out[255]:
array([ 1.57079633, 3.14159265, 4.71238898, 6.28318531, 7.85398163,
9.42477796, 10.99557429, 12.56637061, 14.13716694, 15.70796327])
In [256]: a_11,a_12, a_21, a_22=0,1,-omega_0^2,-c
In [257]: a_11
Out[257]: 0
In [258]: A = np.array([[a_11,a_12], [a_21, a_22]])
In [259]: A
Out[259]:
array([[ 0, 1],
[-3, -1]])
In [260]: t.shape
Out[260]: (10,)
In [261]: A.shape
Out[261]: (2, 2)
In [262]: A_ = np.array([A for k in range (1,n+1,1)])
In [263]: A_.shape
Out[263]: (10, 2, 2)
A_ is np.ndarray. I made A a np.ndarray as well; yours is np.matrix, but your A_ will still be np.ndarray. np.matrix can only be 2d, where as A_ is 3d.
So t * A will be array elementwise multiplication, hence the broadcasting error, (10,) (10,2,2).
To do that elementwise multiplication right you need something like
In [264]: result = t[:,None,None]*A[None,:,:]
In [265]: result.shape
Out[265]: (10, 2, 2)
But if you want matrix multiplication of the (10,) with (10,2,2), then einsum does it easily:
In [266]: result1 = np.einsum('i,ijk', t, A_)
In [267]: result1
Out[267]:
array([[ 0. , 86.39379797],
[-259.18139392, -86.39379797]])
np.dot can't do it because its rule is 'last with 2nd to last'. tensordot can, but I'm more comfortable with einsum.
But that einsum expression makes it obvious (to me) that I can get the same thing from the elementwise *, by summing on the 1st axis:
In [268]: (t[:,None,None]*A[None,:,:]).sum(axis=0)
Out[268]:
array([[ 0. , 86.39379797],
[-259.18139392, -86.39379797]])
Or (t[:,None,None]*A[None,:,:]).cumsum(axis=0) to get a 2x2 for each time.
This is what I would do.
import numpy as np
from scipy.linalg import expm
A = np.array([[1, 2], [3, 4]])
for t in np.linspace(0, 5*np.pi, 20):
print(expm(t*A))
No attempt at vectorization here. The expm function applies to one matrix at a time, and it surely takes the bulk of computation time. No need to worry about the cost of multiplying A by a scalar.

Python Numpy Logistic Regression

I'm trying to implement vectorized logistic regression in python using
numpy. My Cost function (CF) seems to work OK. However there is a
problem with gradient calculation. It returns 3x100 array whereas it
should return 3x1. I think there is a problem with the (hypo-y) part.
def sigmoid(a):
return 1/(1+np.exp(-a))
def CF(theta,X,y):
m=len(y)
hypo=sigmoid(np.matmul(X,theta))
J=(-1./m)*((np.matmul(y.T,np.log(hypo)))+(np.matmul((1-y).T,np.log(1-hypo))))
return(J)
def gr(theta,X,y):
m=len(y)
hypo=sigmoid(np.matmul(X,theta))
grad=(1/m)*(np.matmul(X.T,(hypo-y)))
return(grad)
X is a 100x3 arrray, y is 100x1, and theta is a 3x1 arrray. It seems both functions are working individually, however this optimization function gives an error:
optim = minimize(CF, theta, method='BFGS', jac=gr, args=(X,y))
The error: "ValueError: shapes (3,100) and (3,100) not aligned: 100 (dim 1) != 3 (dim 0)"
I think there is a problem with the (hypo-y) part.
Spot on!
hypo is of shape (100,) and y is of shape (100, 1). In the element-wise - operation, hypo is broadcasted to shape (1, 100) according to numpy's broadcasting rules. This results in a (100, 100) array, which causes the matrix multiplication to result in a (3, 100) array.
Fix this by bringing hypo into the same shape as y:
hypo = sigmoid(np.matmul(X, theta)).reshape(-1, 1) # -1 means automatic size on first dimension
There is one more issue: scipy.optimize.minimize (which I assume you are using) expects the gradient to be an array of shape (k,) but the function gr returns a vector of shape (k, 1). This is easy to fix:
return grad.reshape(-1)
The final function becomes
def gr(theta,X,y):
m=len(y)
hypo=sigmoid(np.matmul(X,theta)).reshape(-1, 1)
grad=(1/m)*(np.matmul(X.T,(hypo-y)))
return grad.reshape(-1)
and running it with toy data works (I have not checked the math or the plausibility of the results):
theta = np.reshape([1, 2, 3], 3, 1)
X = np.random.randn(100, 3)
y = np.round(np.random.rand(100, 1))
optim = minimize(CF, theta, method='BFGS', jac=gr, args=(X,y))
print(optim)
# fun: 0.6830931976615066
# hess_inv: array([[ 4.51307367, -0.13048255, 0.9400538 ],
# [-0.13048255, 3.53320257, 0.32364498],
# [ 0.9400538 , 0.32364498, 5.08740428]])
# jac: array([ -9.20709950e-07, 3.34459058e-08, 2.21354905e-07])
# message: 'Optimization terminated successfully.'
# nfev: 15
# nit: 13
# njev: 15
# status: 0
# success: True
# x: array([-0.07794477, 0.14840167, 0.24572182])

Categories