Creating numpy array of matrices - python

I am trying to create a multi-dimensional numpy array where the data type is a matrix. So, I would like to be able to store a 3x3 numpy matrices into a multi-dimensional array. For example, I would like to create a numpy array of size 100 x 100 x 100, so when I refer to an index like:
x [10, 10, 10] <- should return a 3x3 numpy matrix
I can do something like:
x = np.array((100, 100, 100), np.matrix)
However, I am not sure how to define the size of the matrix in this case. Another option is to do something like:
x = np.array((100, 100, 100, 3, 3))
However, this way I am not able to take advantage of the matrix object class and its functions.
[EDIT]
One thing I now realised is that I can cast an array to numpy matrix. So, using something like:
x = np.array((100, 100, 100, 3, 3))
a = np.matrix(x[1, 1, 1])
However, I wonder if there is a more direct way.
[MORE EDIT]
After reading comments, it seems the numpy matrix class is not really that useful. I can do something like the following to compute the inverse, for example:
x = np.array((100, 100, 100, 3, 3))
a = np.matrix(x[1, 1, 1])
a_inv = np.linalg.inv(a)

Related

Indexing array with array on numpy

It is similar to some questions around SO, but I don't quite understand the trick to get what I want.
I have two arrays,
arr of shape (x, y, z)
indexes of shape (x, y) which hold indexes of interest for z.
For each value of indexes I want to get the actual value in arr where:
arr.x == indexes.x
arr.y == indexes.y
arr.z == indexes[x,y]
This would give an array of shape(x,y) similar to indexes' shape.
For example:
arr = np.arange(99)
arr = arr.reshape(3,3,11)
indexes = np.asarray([
[0,2,2],
[1,2,3],
[3,2,10]])
# indexes.shape == (3,3)
# Example for the first element to be computed
first_element = arr[0,0,indexes[0,0]]
With the above indexes, the expected arrays would look like:
expected_result = np.asarray([
[0,13,24],
[34,46,58],
[69,79,98]])
I tried elements = np.take(arr, indexes, axis=z)
but it gives an array of shape (x, y, x, y)
I also tried things like elements = arr[indexes, indexes,:] but I don't get what I wish.
I saw a few answers involving transposing indexes and transforming it into tuples but I don't understand how it would help.
Note: I'm a bit new to numpy so I don't fully understand indexing yet.
How would you solve this numpy style ?
This can be done using np.take_along_axis
import numpy as np
#sample data
np.random.seed(0)
arr = np.arange(3*4*2).reshape(3, 4, 2) # 3d array
idx = np.random.randint(0, 2, (3, 4)) # array of indices
out = np.squeeze(np.take_along_axis(arr, idx[..., np.newaxis], axis=-1))
In this code, the array of indices gets added one more axis, so it can be broadcasted to the shape of the array arr from which we are making the selection. Then, since the return value of np.take_along_axis has the same shape as the array of indices, we need to remove this extra dimension using np.squeeze.
Another option is to use np.choose, but in this case the axis along which you are making selections must be moved to be the first axis of the array:
out = np.choose(idx, np.moveaxis(arr, -1, 0))
The solution here should work for you: Indexing 3d numpy array with 2d array
Adapted to your code:
ax_0 = np.arange(arr.shape[0])[:,None]
ax_1 = np.arange(arr.shape[1])[None,:]
new_array = arr[ax_0, ax_1, indexes]
You can perform such an operation with np.take_along_axis, the operation can only be applied along one dimension so you will need to reshape your input and indices.
The operation you are looking to perform is:
out[i, j] = arr[i, j, indices[i, j]]
However, we are forced to reshape both arr and indices, i.e. map (i, j) to k, such that we can apply np.take_along_axis. The following operation will take place:
out[k] = arr[k, indices[k]] # indexing along axis=1
The actual usage here comes down to:
>>> put = np.take_along_axis(arr.reshape(9, 11), indices.reshape(9, 1), axis=1)
array([[ 0],
[13],
[24],
[34],
[46],
[58],
[69],
[79],
[91]])
Then reshape back to the shape of indices:
>>> put.reshape(indices.shape)
array([[ 0, 13, 24],
[34, 46, 58],
[69, 79, 91]])

List of 2D-arrays/matrices to 2d array in python

I have a list of arrays with the length 3625, consisting of (101, 101) matrices/2D-arrays which I want to convert/reshape to a 2D array e.g. size (725, 5) or directly into a dataframe with the same size, so that each element in the this new list contains one of those 2d-arrays.
I tried it like this, also with np.ravel and reshape, but I can't seem to get it into the right shape.
list = np.zeros((725,5))
for i in y:
list = np.append(list, [[i]])
Your question is not clear, please try to give more concrete examples. Anyway, as far as I understand you are looking for something like this.
import numpy as np
data = np.zeros((3625, 101, 101))
print(data.shape)
reshaped_data = np.reshape(data, (725, 5, 101, 101))
print(reshaped_data.shape)
Output:
(3625, 101, 101)
(725, 5, 101, 101)

Numpy: slicing a volume using a matrix

I have a 3D numpy volume and a 2D numpy matrix:
foo = np.random.rand(20,20,10)
amin = np.argmin(foo, axis=2)
i would like to use amin variable to slice the volume in the same way np.min would do:
grid = np.indices(min.shape)
idcs = np.stack([grid[0], grid[1], min])
fmin = foo[idcs[0], idcs[1], idcs[2]]
problem is that i can't use np.min because i also need the amin neighbors for interpolation reasons, something that i would obtain doing:
pre = foo[idcs[0], idcs[1], np.clip(idcs[2]-1, 0, 9)]
post = foo[idcs[0], idcs[1], np.clip(idcs[2]+1, 0, 9)]
Is there a more pythonic (nupyic) way to do this without creating an np.grid? something like:
foo[:,:,amin-1:amin+1]
that actually works (i would care about margin handling with an early-padding)
You could use np.ogrid instead of np.indices to save memory.
np.ogrid returns an "open" meshgrid:
In [24]: np.ogrid[:5,:5]
Out[24]:
[array([[0],
[1],
[2],
[3],
[4]]), array([[0, 1, 2, 3, 4]])]
ogrid returns component arrays which can be used as indices
in the same way as one would use np.indices.
NumPy will automatically broadcast the values in the open mesh when they are used as indices:
In [49]: (np.indices((5,5)) == np.broadcast_arrays(*np.ogrid[:5, :5])).all()
Out[49]: True
import numpy as np
h, w, d = 20, 20, 10
foo = np.random.rand(h, w, d)
amin = np.argmin(foo, axis=2)
X, Y = np.ogrid[:h, :w]
amins = np.stack([np.clip(amin+i, 0, d-1) for i in [-1, 0, 1]])
fmins = foo[X, Y, amins]
It's better to store fmin, pre and post in one array, fmins,
since some NumPy/Scipy operations (like argmin or griddata) may need the values in one array. If, later, you need to operate on the 3 components individually, you can always access them using fmins[i] or define
pre, fmin, post = fmins

Programmatically cropping an array along all its axes in Numpy

I want to (uniformly) reduce the dimensions of a numpy array (matrix) in each direction. The code below works.
array = np.array([3, 2323, 212, 2321, 54])
padding = 1
array[padding:-padding]
Output:
[2323, 12, 2321]
But I want this to be done another way. My array will be 50-dimensional and I want to apply the last line to each dimension of the array, but I don't want to write much code.
Maybe something like
array[padding: -padding for i in range(50)]
But it doesn't work.
You can produce the relevant slices directly;
array[array.ndim * [slice(1, -1)]]
For instance,
In [31]: array = np.zeros((3, 4, 5, 6))
In [32]: array[array.ndim * [slice(1, -1)]].shape
Out[32]: (1, 2, 3, 4)

Numpy operate over 2D array to produce 3D array

I have generated a numpy array of (x, y) values as a N x N grid.
grid = np.meshgrid(np.linspace(0, 1, 50), np.linspace(0, 1, 50))[0]
grid.shape // (50, 50, 1)
I have a function that takes two parameters and returns 3 values.
i.e. (x, y) -> (a, b, c)
How to I apply the function over the 2d numpy array to get a 3d numpy array?
If your function really takes two parameters you probably want to map not 2d to 3d, but rather 2xMxN to 3xMxN. For this change your first line to something like
gridx, gridy = np.meshgrid(np.linspace(0, 1, 50), np.linspace(0, 1, 50))
or even use the more economical ix_ which has the advantage of not swapping axes
gridy, gridx = np.ix_(np.linspace(0, 1, 50), np.linspace(0, 1, 50))
If your function f does not handle array arguments then as #Jacques Gaudin points out np.vectorize is probably what you want. Be warned that vectorize is primarily a convenience function it doesn't make things faster. It does useful things like broadcasting which is why using ix_ actually works
f_wrapped = np.vectorize(f)
result = f_wrapped(gridy, gridx)
Note that result in your case is a 3-tuple of 50 x 50 arrays, i.e. is grouped by output. This is convenient if you want to chain vectorized functions. If you want all in one big array just convert result to array and optionally use transpose to rearrange axes, e.g.
triplets_last = np.array(result).transpose((1, 2, 0))
If I understand correctly, you are after the np.vectorize decorator. By using it you can apply a function over a meshgrid. Your function should take only one parameter though as you do not pass the coordinates but the value at the coordinates (unless the values are tulpes with two elements).
import numpy as np
grid = np.meshgrid(np.linspace(0, 1, 5), np.linspace(0, 1, 5))[0]
#np.vectorize
def func(a):
return (a, a**.5, a**2)
res = np.array(list(func(grid)))
print(res.shape)
print(res)

Categories

Resources