The code below is meant to conduct a linear coordinate transformation on a set of 3d coordinates. The transformation matrix is A, and the array containing the coordinates is x. The zeroth axis of x runs over the dimensions x, y, z. It can have any arbitrary shape beyond that.
Here's my attempt:
A = np.random.random((3, 3))
x = np.random.random((3, 4, 2))
x_prime = np.einsum('ij,j...->i...', A, x)
The output is:
x_prime = np.einsum('ij,j...->i...', A, x)
ValueError: operand 0 did not have enough dimensions
to match the broadcasting, and couldn't be extended
because einstein sum subscripts were specified at both
the start and end
If I specify the additional subscripts in x explicitly, the error goes away. In other words, the following works:
x_prime = np.einsum('ij,jkl->ikl', A, x)
I'd like x to be able to have any arbitrary number of axes after the zeroth axis, so the workaround I give about is not optimal. I'm actually not sure why the first einsum example is not working. I'm using numpy 1.6.1. Is this a bug, or am I misunderstanding the documentation?
Yep, it's a bug. It was fixed in this pull request: https://github.com/numpy/numpy/pull/4099
This was only merged a month ago, so it'll be a while before it makes it to a stable release.
EDIT: As #hpaulj mentions in the comment, you can work around this limitation by adding an ellipsis even when all indices are specified:
np.einsum('...ij,j...->i...', A, x)
Related
I have some object y.
If directed, y a tuple (y0, y1) of shape (n, d) arrays.
If not directed, y is a single array of shape (n, d).
Furthermore, y/y0/y1 of type np.ndarray can be either 1d or 2d. If 1d, I want its length. If 2d, I want the second value of its shape.
I'm trying to think of the simplest code that accounts for all of this and gives me the value of d. So far, the simplest I have is
_, d = np.atleast_2d(y[0]).shape if directed else np.atleast_2d(y).shape
but this feels a little obtuse. Can anyone think of a better way of doing this?
Unless you have a budget for the number of lines you're allowed to use, then something like this is nice and simple (you could even add explanatory comments for bonus points):
if directed:
[y0, y1] = y
d = y0.shape[-1]
assert y1.shape[-1] == d
else:
d = y.shape[-1]
I am not very familiar with tensor algebra and I am having trouble understanding how to make numpy.tensordot do what I want.
The example I am working with is simple: given a tensor a with shape (2,2,3) and another b with shape (2,1,3), I want a result tensor c with shape (2,1). This tensor would be the result of the following, equivalent python code:
n = a.shape[2]
c = np.zeros((2,n))
for k in range(n):
c += a[:,:,k]*b[:,:,k]
The documentation says that the optional parameter axes:
If an int N, sum over the last N axes of a and the first N axes of b in order. The sizes of the corresponding axes must match.
But I don't understand which "axes" are needed here (furthermore, when axes is a tuple or a tuple of tuples it gets even more confusing). Examples aren't very clear to me either.
The way tensordot works, it won't work here (not at least directly) because of the alignment requirement along the first axes. You can use np.einsum though to solve your case -
c = np.einsum('ijk,ilk->ij',a,b)
Alternatively, use np.matmul/#-operator (Python 3.x) -
np.matmul(a,b.swapaxes(1,2))[...,0] # or (a # b.swapaxes(1,2))[...,0]
I am solving a linear system of equations Ax=b.
It is known that A is square and of full rank, but it is the result of a few matrix multiplications, say A = numpy.dot(C,numpy.dot(D,E)) in which the result can be 1x1 depending on the inputs C,D,E. In that case A is a float.
b is ensured to be a vector, even when it is a 1x1 one.
I am currently doing
A = numpy.dot(C,numpy.dot(D,E))
try:
x = numpy.linalg.solve(A,b)
except:
x = b[0] / A
I searched numpy's documentation and didn't find other alternatives for solve and dot that would accept scalars for the first or output arrays for the second. Actually numpy.linalg.solve requires dimension at least 2. If we were going to produce an A = numpy.array([5]) it would complain too.
Is there some alternative that I missed?
in which the result can be 1x1 depending on the inputs C,D,E. In that case A is a float.
This is not true, it is a 1x1 matrix, as expected
x=np.array([[1,2]])
z=x.dot(x.T) # 1x2 matrix times 2x1
print(z.shape) # (1, 1)
which works just fine with linalg.solve
linalg.solve(z, z) # returns [[1]], as expected
While you could expand the dimensions of A:
A = numpy.atleast_2d(A)
it sounds like A never should have been a float in the first place, and you should instead fix whatever is causing it to be one.
What is the proper way of computing the covariance matrix of two matices, X of shape (n x p) and Y of shape (n x q)
import numpy as np
X = np.array([np.random.normal(size=10),
np.random.normal(size=10),
np.random.normal(size=10)]).T
Y = np.array([np.random.normal(size=10),
np.random.normal(size=10),
np.random.normal(size=10),
np.random.normal(size=10)]).T
Doing np.cov(X,Y) returns an error.
But np.cov(X.T, Y.T) does not
What is the reason for this?
From the documentation:
y : array_like, optional
An additional set of variables and observations.
y has the same form as that of m.
The shape of the matrices is not equal. I suppose the numpy authors forgot to check the dimensions in the first case. I have no other explanation for that. Possibly the computations are run on a subarray of Y in the first case. Possibly this is already fixed in newer version of numpy or you can consider to send a bug report.
I have a cubic grid defined by the spacing xi,yi,zi:
xi,yi,zi = [linspace(ox,ox+s*d,s) for ox,s,d in zip(origin,size,delta)]
I also have set of scalar values W onto that grid. W.shape() == size. I'd like to use scipy's linear interpolation, which requires as input:
class scipy.interpolate.LinearNDInterpolator(points, values):
Parameters :
points : ndarray of floats, shape (npoints, ndims) Data point coordinates.
values : ndarray of float or complex, shape (npoints, ...) Data values.
How do I create a fake set of points (via magical broadcasting) from xi,yi,zi? Right now I'm creating an intermediate array to feed to the interpolation function - is there a better way?
Related Question: Numpy meshgrid in 3D. The answers in this post actually create the grid - I only want to simulate it as input to another function (pure numpy solution preferred).
>>> xi, yi, zi = [np.arange(3) for i in range(3)]
>>> xx, yy, zz = np.broadcast_arrays(xi,yi[:,np.newaxis],zi[:,np.newaxis,np.newaxis])
>>> xx.shape
(3, 3, 3)
>>> xx.strides
(0, 0, 8)
You can see it didn't create new copies since the strides are 0 in the first two dimensions.
I wrote a n dimensional version of this also:
def ndmesh(*args):
args = map(np.asarray,args)
return np.broadcast_arrays(*[x[(slice(None),)+(None,)*i] for i, x in enumerate(args)])
You can construct the necessary points array in a similar way as explained in the other answers:
xx, yy, zz = np.broadcast_arrays(xi[:,None,None], yi[None,:,None], zi[None,None,:])
points = (xx.ravel(), yy.ravel(), zz.ravel())
ip = LinearNDInterpolator(points, data.ravel())
However, if you have a regular grid, then using LinearNDInterpolator is most likely not the best choice, since it is designed for scattered data interpolation. It constructs a Delaunay triangulation of the data points, but in this case the original data has already a very regular structure that would be more efficient to make use of.
Since your grid is rectangular, you can build up the interpolation as a tensor product of three 1-D interpolations. Scipy doesn't have this built-in (so far), but it's fairly easy to do, see this thread: http://mail.scipy.org/pipermail/scipy-user/2012-June/032314.html
(use e.g. interp1d instead of pchip to get 1-D interpolation)
I do not believe there is any way you can pass something to LinearNDInterpolator short of a full copy (as there are no functions for regular grids in three dimensions too). So the only place to avoid creating full arrays would be during creation of this points array, I do not know how you do it right now, so maybe it is already efficient in this regard, but I guess its likely not worth the trouble to avoid this.
Other then np.mgrid+reshape maybe something like this might be an option (not to hard to write for n-dimensions too):
# Create broadcastest versions of xi, yi and zi
# np.broadcast_arrays does not allocate the full arrays
xi, yi, zi = np.broadcast_arrays(xi[:,None,None], yi[:,None,None], zi[:,None,None])
# then you could use .flat to fill a point array:
points = np.empty((xi.size, 3), dtype=xi.dtype)
points[:,0] = xi.flat
points[:,1] = yi.flat
points[:,2] = zi.flat
Opposed to the .repeat function, the temporary arrays created here are not larger then the original xi, etc. arrays.