Python, from matrix to array - python

I have a 3d matrix grid_z0, whose dimension are (let's say) 50x25x36. Each point of this matrix represents a cell. I would like to convert this matrix into a 1D array of size 50x25x36. I would also like to create 3 array of the same size showing the coordinate of the cell center.
The array cx,cy and cz stores the coordinate of the cell center in one direction.
This example work but it rather slow, especially for large data set. Is there a way to make it faster?
data={"x":[],"y":[],"z":[],"rho":[]}
for i in arange(0,50):
for j in arange(0,25):
for k in arange(0,36):
data["x"].append(cx[i])
data["y"].append(cy[j])
data["z"].append(cz[k])
data["f"].append(grid_z0[i][j][k])

You should consider using NumPy.
>>> import numpy as np
>>> a = np.random.rand(50,25,36) # Create a fake array
>>> print a.shape
(50, 25, 36)
>>> a.shape = -1 # Flatten the array in place
>>> print a.shape
(45000,)
When flattening your array, you're doing the equivalent of :
>>> b = []
>>> for i in range(a.shape[0]):
... for j in range(a.shape[1]):
... for k in range(a.shape[2]):
... b.append(a[i,j,k])
That is, the last axis is parsed first, then the second, then the first.
Given your three 1D lists cx, cy, cz of length N, you can construct a 2D array with:
>>> centers = np.array([cx,cy,cz])
>>> print centers.shape
(3, N)

Use Numpy for matrix/array manipulation.
# convert to 1D array :
grid_1d = np.asarray(grid_z0).ravel()
For the second question, you need a 3D meshgrid. See here for an exemple :
Numpy meshgrid in 3D

Related

How to gather arrays of different sizes in the same array with Numpy?

Context: I have 3 arrays. A that is 3x3, B that is 5x2, and C that is a 3D array.
Question: Is there a way to stack arrays of different sizes along the 1st dimension of a 3D array, with Numpy ?
Example: if A and B are stacked in C along its first dimension, and I want to access A, I would type C[0].
Problem: I know I can use Xarray for that, but I wanted to know if there was a Numpy way to do it. So far, I have been artificially extending the arrays with NaNs to match their sizes (see code below).
Code:
# Generate the arrays
A = np.random.rand(3,3)
B = np.random.rand(5,2)
C = np.zeros((2,5,3))
# Resize the arrays to fit C
AR = np.full([C.shape[1], C.shape[2]], np.nan) # Generate an array full of NaNs that fits C
AR[:A.shape[0],:A.shape[1]] = A # Input the previous array in the resized one
BR = np.full([C.shape[1], C.shape[2]], np.nan) # Generate an array full of NaNs that fits C
BR[:B.shape[0],:B.shape[1]] = B # Input the previous array in the resized one
# Stack the resized arrays in C
C[0] = AR
C[1] = BR
You won't be able to slice it as freely, but you can use dtype = 'object' when making a jagged array.
jagged_array = np.array([np.zeros((3, 2)), np.zeros((5, 2)), np.zeros((3, 2, 5))], dtype = 'object')

Easiest way to sample from a multidimensional array with another multidimensional array in python

I have a 3d numpy array that looks like this
A = np.random.randin(0, 10, (23, 23, 39)) # H, W, D
And wish to random sample from its depth to reach a 2d array with H and W only
Note … this doesn't work
B = A[np.random.randint(0, 39, (23,23))]
I think this is what you're looking for:
B = np.array([x[np.random.randint(A.shape[2])] for y in A for x in y]).reshape(A.shape[:-1])
A little explanation: we use list comprehension to iterate, two dimensionally, over every sub-array in the list (y iterates over dimension 0, x iterates over dimension 1, we get arrays of dimension 2)
In each of these arrays, we then take a random number.
The result is a large one dimensional array containing one element from each sub-array. We finally resize the array so it is the shape of A, minus the last dimension (in our case, 23 x 23)|
Hope it's what you're looking for!

How to multiply two 3d numpy arrays along some particular axis?

Suppose we have two numpy arrays: A with shape (n,p,q), B with shape (n,q,r).
How to multiply them to get an array C with shape (n,p,r)? I mean keep axis 0 and multiply them by axis 1 and 2.
I know it can be computed by:
C = np.stack([np.dot(a[i], b[i]) for i in range(A.shape[0])])
But does there exist a numpy function which can be used to compute it directly?
I think you can do np.einsum:
# sample data
n,p,q,r = 2,3,4,5
A = np.zeros((n,p,q))
B = np.zeros((n,p,r))
out = np.einsum('npq,nqr->npr',A,B)
out.shape
# (2, 3, 5)

numpy/scipy: fill upper triangle of array with elements of 1d vector?

Say I have a flattened 1D vector that exactly corresponds to the upper triangle elements of a 2D array.
The 1D vector needs to be read into the upper triangle.
I might do the following in python:
triu_flat = ...
row,col = np.triu_indices(50)
D = np.zeros((50,50))
i=0
for r in row:
for c in col:
D[r,c] = triu_flat[i]
i++
However, there must be a way to do this via numpy/scipy operations.
You can simply use the indices returned by triu_indices(), no need for a for loop:
import numpy
data = numpy.arange(6)
out = numpy.zeros((3, 3))
inds = numpy.triu_indices(len(out))
out[inds] = data

Delete 2d subarray from 3d array in numpy

In numpy I have a 3d array and I would ike to remove some of the 2d subarrays. Think about it like this:
r = range(27)
arr = np.reshape(r, (3,3,3))
del = [[0,1,2],[0,0,2]]
flatSeam = np.ravel_multi_index(del, arr.shape)
arr = np.delete(arr, flatSeam)
So at the end I would like to have an array of the shape (3,2,3) without the elements 00, 10, 22 from the original array. My problem is that I acn not use ravel_multi_index for this, because my indices are 2d and the array shape is 3d, so the wrong indices are calculated (the code above also does not execute because the indices array and the shape have to be the same size).
Do you have any ideas how I can achieve this?
Here's an approach using advanced-indexing -
# arr: Input array, rm_idx : 2-row list/array of indices to be removed
m,n,p = arr.shape
mask = np.asarray(rm_idx[1])[:,None] != np.arange(n)
out = arr[np.arange(m)[:,None],np.where(mask)[1].reshape(m,-1)]
Alternatively, with boolean-indexing -
out = arr.reshape(-1,p)[mask.ravel()].reshape(m,-1,p)
A bit less memory-intensive approach as we try to avoid creating 2D mask -
vmask = ~np.in1d(np.arange(m*n),rm_idx[1] + n*np.arange(m))
out = arr.reshape(-1,p)[vmask].reshape(m,-1,p)

Categories

Resources