What does 'M' means on scipy document? - python

I love numpy and scipy and often read those documents. For instance, according to the page describing about numpy.linalg.inv, inv takes a parameter of which type is array_like.
But, I do not know what (..., M, M) means put before array_like. Please let me know what is this.

It means that the operations will be performed for the last two axes of the input array and that the last two axes must be of the same size M.
So if you have an input array with 3 axes of shape n, M, M, it will return the inverse of the n 2D arrays of shape M, M, taken from the last 2 axes.

Related

Sample more than one element from multivariable normal distribution

I have a 2D means matrix in size n*m, where n is number of samples and m is the dimension of the data.
I have as well n matrices of m*m, namely sigma is my variance matrix in shape n*m*m.
I wish to sample n samples from a the distributions above, such that x_i~N(mean[i], sigma[i]).
Any way to do that in numpy or any other standard lib w/o running with a for loop?
The only option I thought was using np.random.multivariate_normal() by flatting the means matrix to one vector, and flatten the 3D sigma to a 2D blocks-diagonal matrix. And of course reshape afterwards. But that means we are going the sample with sigma in shape (n*m)*(n*m) which can easily be ridiculously huge, and only computing and allocating that matrix (if possible) can take longer than running in a for loop.
In my specific task, right now Sigma is the same matrix for all the samples, means I can express Sigma in m*m, and it is the same one for all n points. But I am interested in a general solution.
Appreciate your help.
Difficult to tell without testable code, but this should be close:
A = numpy.linalg.cholesky(sigma) # => shape (n, m, m), same as sigma
Z = np.random.normal(size = (n, m)) # shape (n, m)
X = np.einsum('ijk, ik -> ij', A, Z) + mean # shape (n, m)
What's going on:
We're manually sampling multivariate normal distributions according to the standard Cholesky decomposition method outlined here. A is built such that A#A.T = sigma. Then X (the multivariate normal) can be formed by the dot product of A and a univariate normal N(0, 1) vector Z, plus the mean.
You keep the extraneous dimension throughout the calculation in the first (index = 0, 'i' in the einsum) axis, while contracting the last ('k') axis, forming the dot product.

What does the 'axis' parameter in numpy.fft.fft mean?

The Fast Fourier Transform (fft; documentation) transforms 'a' into its fourier, spectral equivalent:
numpy.fft.fft(a, n=None, axis=-1, norm=None)
The parameter, n represents—so far as I understand it—how many samples are in the output, where the output is either cropped if n is smaller than the number of samples in a, or padded with zeros if n is larger.
What does axis do? What does it mean exactly? I haven't been able to find any clear examples of its use.
np.fft.fft computes the one-dimensional discrete Fourier transform. If you give a one dimensional input (a vector), it will just compute the transform for that input. However, if your input has more than one dimension, like a 2D matrix, or higher, NumPy assumes you are giving many vectors and you want to compute the transform of each of them. The axis parameter indicates the dimension corresponding to those vectors, and by default it is the last one (-1). So, for example, for a 2D matrix m, if axis=0 then each column m[:, 0], m[:, 1], etc. would be the vectors for which the transform is computed, while passing axis=1 (equivalent to the default axis=-1), each row m[0, :], m[1, :], etc. would be considered a vector for the transform. If you want to compute the transform of all values in the input, regardless of the dimensions, you would have to flatten the input, for example with np.ravel.
Btw, this is a very common convention in NumPy (and many other algebra packages), where a one-dimensional operation can work on multidimensional inputs by receiving an axis parameter that indicates the dimension over which the operation is performed.
numpy.fft.fft() returnes a one-dimensional fourier-transform of your array. That means if you have an array of shape (N,M) it will not give you a two-dimensional fft (np.fft.fft2() does) but return the fft along the last axis. If you like to have the fft calculated rather along the columns than the rows you should pass axis=0.

Numpy: Perform Multiplication-like Addition

I wanted to define my own addition operator that takes an Nx1 vector (call it A) and a 1xN vector (B) such that the element in the i^th row and j^th column is the sum of the i^th element in A and the j^th element in B. An example is illustrated here.
I was able to write the following code for the function (and it is correct as far as I know).
def test_fn(a, b):
a_len = a.shape[0]
b_len = b.shape[1]
prod = np.array([[0]*a_len]*b_len)
for i in range(a_len):
for j in range(b_len):
prod[i, j] = a[i, 0] + b[0, j]
return prod
However, the vectors I am working with contain thousands of elements, and the function above is quite slow. I was wondering if there was a better way to approach this problem, or if there was a numpy function that could be of use. Any help would be appreciated.
According to numpy's broadcasting rules, you can use a+b to implement your own defined operator.
The first rule of broadcasting is that if all input arrays do not have the same number of dimensions, a “1” will be repeatedly prepended to the shapes of the smaller arrays until all the arrays have the same number of dimensions.
The second rule of broadcasting ensures that arrays with a size of 1 along a particular dimension act as if they had the size of the array with the largest shape along that dimension. The value of the array element is assumed to be the same along that dimension for the “broadcast” array.

Solve broadcasting error without for loop, speed up code

I may be misunderstanding how broadcasting works in Python, but I am still running into errors.
scipy offers a number of "special functions" which take in two arguments, in particular the eval_XX(n, x[,out]) functions.
See http://docs.scipy.org/doc/scipy/reference/special.html
My program uses many orthogonal polynomials, so I must evaluate these polynomials at distinct points. Let's take the concrete example scipy.special.eval_hermite(n, x, out=None).
I would like the x argument to be a matrix shape (50, 50). Then, I would like to evaluate each entry of this matrix at a number of points. Let's define n to be an a numpy array narr = np.arange(10) (where we have imported numpy as np, i.e. import numpy as np).
So, calling
scipy.special.eval_hermite(narr, matrix)
should return Hermitian polynomials H_0(matrix), H_1(matrix), H_2(matrix), etc. Each H_X(matrix) is of the shape (50,50), the shape of the original input matrix.
Then, I would like to sum these values. So, I call
matrix1 = np.sum( [scipy.eval_hermite(narr, matrix)], axis=0 )
but I get a broadcasting error!
ValueError: operands could not be broadcast together with shapes (10,) (50,50)
I can solve this with a for loop, i.e.
matrix2 = np.sum( [scipy.eval_hermite(i, matrix) for i in narr], axis=0)
This gives me the correct answer, and the output matrix2.shape = (50,50). But using this for loop slows down my code, big time. Remember, we are working with entries of matrices.
Is there a way to do this without a for loop?
eval_hermite broadcasts n with x, then evaluates Hn(x) at each point. Thus, the output shape will be the result of broadcasting n with x. So, if you want to make this work, you'll have to make n and x have compatible shapes:
import scipy.special as ss
import numpy as np
matrix = np.ones([100,100]) # example
narr = np.arange(10) # example
ss.eval_hermite(narr[:,None,None], matrix).shape # => (10, 100, 100)
But note that this might actually be faster:
out = np.zeros_like(matrix)
for n in narr:
out += ss.eval_hermite(n, matrix)
In testing, it appears to be between 5-10% faster than np.sum(...) of above.
The documentation for these functions is skimpy, and a lot of the code is compiled, so this is just based on experimentation:
special.eval_hermite(n, x, out=None)
n apparently is a scalar or array of integers. x can be an array of floats.
special.eval_hermite(np.ones(5,int)[:,None],np.ones(6)) gives me a (5,6) result. This is the same shape as what I'd get from np.ones(5,int)[:,None] * np.ones(6).
The np.ones(5,int)[:,None] is a (5,1) array, np.ones(6) a (6,), which for this purpose is equivalent of (1,6). Both can be expanded to (5,6).
So as best I can tell, broadcasting rules in these special functions is the same as for operators like *.
Since special.eval_hermite(nar[:,None,None], x) produces a (10,50,50), you just apply sum to axis 0 of that to produce the (50,50).
special.eval_hermite(nar[:,Nar,Nar], x).sum(axis=0)
Like I wrote before, the same broadcasting (and summing) rules apply for this hermite as they do for a basic operation like *.

OpenCV-Python: What is correct shape of points for finding epipolar lines?

I'm having trouble using the computeCorrespondEpilines() function in OpenCV-Python. According to the documentation, the matrix of points is described as:
"Input points. N x 1 or 1 x N matrix of type CV_32FC2 or vector< Point2f >"
However, I'm not sure what this means in Python. I tried using a list of tuples but it was not a Numpy array, so I tried a Numpy array of tuples but it automatically converts to a Nx2 matrix. I also tried a Numpy structured array as a list of tuples, but the epilines function then says "points data type = 20 is not supported" which literally has 0 results in Google.
Does anyone know what is the correct shape/type of the matrix of points needed for this function?
There seems to be a catch. The type CV_32FC2 is actually a type which contains two channels (values). The same goes with the vector.
So, actually it seems that the function is expecting 3D data with shape (N, 1, 2) or (1, N, 2). If you have a N x 2 matrix M, then you may use this:
MM = M.reshape((1,-1,2))
This should give a suitable array MM with shape (1, N, 2). If that does not work, then try:
MM = M.reshape((-1,1,2))
which gives a (N, 1, 2) array.
Also, cv2 may be very picky about the data type, so you may try to cast your points into the correct type:
MM = M.reshape((-1,1,2)).astype('float32')
as well.

Categories

Resources