numpy.concatenate multidimensional arrays - python

I'm searching for an algorithm to merge a given number of multidimensional arrays (each of the same shape) to a given proportion (x,y,z).
For example 4 arrays with the shape (128,128,128) and the proportion (1,1,4) to an array of the shape (128,128,512).
Or 2 arrays with the shape (64,64,64) and the proportion (1,2,1) to an array of the shape (64,128,64)
I know how to do it manually with np.concatenate, but I need a general algorithm to do this. (np.reshape doesn't work - this will mess up the order)
edit: It's possible that the proportion is (1,2,3), then it is necessary to compare the left_edge of the box, to know where to place it. every array have a corresponding block with the attribute left_edge (xmin, ymin, zmin). Can I solve this with a if-condition?

If your proportion is always one-dimensional (i.e. concatenate in one dimension only), you can use this:
arrays = [...]
proportion = (1,1,4)
np.concatenate(arrays, axis=next(i for i,p in enumerate(proportion) if p>1))
Otherwise you have to explain what to do with proportion = (1,2,3)

Okay I programmed it this way and it seems to work. Maybe not the nicest way, but it do what I want.
blocks.sort(key=lambda x: (x.left_edge[2],x.left_edge[1],x.left_edge[0]))
proportion = (Nx * nblockx, Ny * nblocky, Nz * nblockz)
arrays = np.zeros((nblockx, nblocky, nblockz, Nx, Ny, Nz))
for block, (x,y,z) in zip(root_list,
product(range(nblockx),
range(nblocky),
range(nblockz))):
array = np.zeros((Nx, Ny, Nz), dtype = np.float64)
# this is only the function to fill the array
writearray(array, ...)
arrays[x,y,z] = array
shape = arrays.shape
array = np.zeros((shape[0]*shape[3], shape[1]*shape[4], shape[2]*shape[5]))
for x,y,z in product(range(shape[0]), range(shape[1]), range(shape[2])):
slicex = slice(x*shape[3], (x+1)*shape[3])
slicey = slice(y*shape[4], (y+1)*shape[4])
slicez = slice(z*shape[5], (z+1)*shape[5])
array[slicex, slicey, slicez] = arrays[x,y,z]
return array

Related

Element wise divide like MATLAB's ./ operator?

I am trying to normalize some Nx3 data. If X is a Nx3 array and D is a Nx1 array, in MATLAB, I can do
Y = X./D
If I do the following in Python, I get an error
X = np.random.randn(100,3)
D = np.linalg.norm(X,axis=1)
Y = X/D
ValueError: operands could not be broadcast together with shapes (100,3) (100,)
Any suggestions?
Edit: Thanks to dm2.
Y = X/D.reshape((100,1))
Another way is to use scikitlearn.
from sklearn import preprocessing
Y = preprocessing.normalize(X)
From numpy documentation on array broadcasting:
When operating on two arrays, NumPy compares their shapes
element-wise. It starts with the trailing (i.e. rightmost) dimensions
and works its way left. Two dimensions are compatible when
they are equal, or
one of them is 1
Both of your arrays have the same first dimension, but your X array is 2-dimensional, while your D array is 1-dimensional, which means the shapes of these two arrays do not meet the requirements to be broadcast together.
To make sure they do, you could reshape your D array into a 2-dimensional array of shape (100,1), which would satisfy the requirements to broadcast: rightmost dimensions are 3 and 1 (one of them is 1) and the other dimensions are equal (100 and 100).
So:
Y = X/D.reshape((-1,1))
or
Y = X/D.reshape((100,1))
or
Y = X/D[:,np.newaxis]
Should give you the result you're after.

Numpy slicing with container (e.g. tuple or list)

I am trying to slice a nD numpy.ndarray. Assume that it is 3D for the sake of simplicity (but in fact it could have been 4D, 5D, etc.) and is composed by nx, ny, nz dimensions.
I would like to extract all nx rows for a given point ny, nz, using a container (e.g. a tuple or list) to select ny and nz.
Example:
Say I have a 3D array X of dimension: (46841, 128, 20), and I have a container = (127,11)
Desired solution:
x_selected = X[:,container]
where x_selected should have dimensions (46841,)
x_selected = X[(slice(None),) + container]
You can thus index X array with any tuple that contains a mixture of slices and integers. slice is just a pure python object described here. This tuple for indexing should have not more elements than dimensions of X array.
you can just use this :
x_selected=X[:,container[0],container[1]]
I tried with this :
A=np.zeros((3,5,7))
A[1,2,:].shape
And I got (7,) as the output

Unravel 1D list back to 3D array

Basically, is there a way to transform a 1D list that has been "flattened" through the numpy.ravel() function back to it's original 3D form ? I know the dimensions, and one might ask why I just don't use the original 3D array in the first place, instead of converting it - but there reasons for that.
I just need to know if I can actually create the same 3D array from a 1D array that was created by using numpy.ravel() on the 3D array.
Basically the 3D array was created like this:
import numpy as np
nx = 50
ny = 40
nz = 150
x = np.linspace(1, 51, nx)
y = np.linspace(1, 41, ny)
z = np.linspace(1, 151, nz)
x_bc = x[:, np.newaxis, np.newaxis]
y_bc = y[np.newaxis, :, np.newaxis]
z_bc = z[np.newaxis, np.newaxis, :]
arr = x_bc + y_bc + z_bc
And nope, I can't just do this to get it back, since calculations has been done to it in the mean time, and then converted to a 1D array in the mean time as well. So the data in this array is not the same as the one I actually want to convert back.
Just reshape it back to the original shape?
raveled = np.ravel(arr)
new_arr = raveled.reshape(*arr.shape)
Does numpy.reshape do what you want?

Reshape from flattened indices in Python

I have an image of size M*N whose pixels coordinates has been flattened to a 1D array according to a space-filling curve (i.e. not a classical rasterization where I could have used reshape).
I thus process my 1D array (flattened image) and I then would like to reshape it to a M*N array (initial size).
So far, I have done this with a for-loop:
for i in range(img_flat.size):
img_res[x[i], y[i]] = img_flat[i]
x and y being the x and y pixels coordinates according to my path scan.
However, I am wondering how to do this in a unique line of code.
If x and y are numpy arrays of dimension 1 and lengths n, and img_flat also has length n img_res is a numpy array of dimension 2 (h, w) such that `h*w = n, then:
img_res[x, y] = img_flat
Should suffice
In fact, it was easy:
vec = np.arange(0, seg.size, dtype=np.uint)
img_res[x[vec], y[vec]] = seg[vec]

Numpy function to get shape of added arrays

tl;dr: How do I predict the shape returned by numpy broadcasting across several arrays without having to actually add the arrays?
I have a lot of scripts that make use of numpy (Python) broadcasting rules so that essentially 1D inputs result in a multiple-dimension output. For a basic example, the ideal gas law (pressure = rho * R_d * temperature) might look like
def rhoIdeal(pressure,temperature):
rho = np.zeros_like(pressure + temperature)
rho += pressure / (287.05 * temperature)
return rho
It's not necessary here, but in more complicated functions it's very useful to initialize the array with the right shape. If pressure and temperature have the same shape, then rho also has that shape. If pressure has shape (n,) and temperature has shape (m,), I can call
rhoIdeal(pressure[:,np.newaxis], temperature[np.newaxis,:])
to get rho with shape (n,m). This lets me make plots with multiple values of temperature without having to loop over rhoIdeal, while still allowing the script to accept arrays of the same shape and compute the result element-by-element.
My question is: Is there a built-in function to return the shape compatible with several inputs? Something that behaves like
def returnShape(list_of_arrays):
return np.zeros_like(sum(list_of_arrays)).shape
without actually having to sum the arrays? If there's no built-in function, what would a good implementation look like?
You could use np.broadcast. This function returns an object encapsulating the result of broadcasting two or more arrays together. No actual operation (e.g. addition) is performed - the object simply has some of the same attributes that an array produced by means of other operations would have (shape, ndim, etc.).
For example:
x = np.array([1,2,3]) # shape (3,)
y = x.reshape(3,1) # shape (3, 1)
z = np.ones((5,1,1)) # shape (5, 1, 1)
Then you can check what the shape of the array returned by broadcasting x, y and z would be by inspecting the shape attribute:
>>> np.broadcast(x, y, z).shape
(5, 3, 3)
This means that you could implement your function simply as follows:
def returnShape(*args):
return np.broadcast(*args).shape

Categories