Python reshape to Matlab reshape translation - python

I have the following Python code that I would like to run in MATLAB. What is the MATLAB equivalent of numpy's reshape syntax.
import numpy as np
a = np.random.randn(3,4,5)
for i in range(len(a)):
b = np.reshape(a, [a.shape[i], -1], order = 'F')

Instead of -1 for a calculated dimension, you would simply use [] in MATLAB.
for k = 1:ndims(a)
b = reshape(a, size(a, k), []);
end

Related

Achieving add operation that maps shapes (a,d) + (b,d) to (a*b,d)

I have a numpy array with shape (a,d) and one with shape (b,d). I want to add all possible combinations of the first axis together, i.e. my final array should have shape (a*b,d). This can achieved using the following code:
import numpy as np
a = 2
b = 2
d = 3
matrix1 = np.random.rand(a,d)
matrix2 = np.random.rand(b,d)
result = np.zeros((a*b,d))
for i in range(a):
result[i*b:i*b+b] = matrix1[i,:] + matrix2
But I would like to do it without a for loop, and using numpy functions only. Is there an easy way to do this? Perhaps using np.einsum or np.meshgrid?
Here you go, use repeat and tile:
result = np.repeat(a,b.shape[0],axis=0) + np.tile(b,(a.shape[0],1))

Efficient way of constructing a 3D stack of block diagonal matrix in numpy/scipy from a 3D stack of matrices

I am trying to construct a stack of block diagonal matrix in the form of nXMXM in numpy/scipy from a given stacks of matrices (nXmXm), where M=k*m with k the number of stacks of matrices. At the moment, I'm using the scipy.linalg.block_diag function in a for loop to perform this task:
import numpy as np
import scipy.linalg as linalg
a = np.ones((5,2,2))
b = np.ones((5,2,2))
c = np.ones((5,2,2))
result = np.zeros((5,6,6))
for k in range(0,5):
result[k,:,:] = linalg.block_diag(a[k,:,:],b[k,:,:],c[k,:,:])
However, since n is in my case getting quite large, I'm looking for a more efficient way than a for loop. I found 3D numpy array into block diagonal matrix but this does not really solve my problem. Anything I could imagine is transforming each stack of matrices into block diagonals
import numpy as np
import scipy.linalg as linalg
a = np.ones((5,2,2))
b = np.ones((5,2,2))
c = np.ones((5,2,2))
a = linalg.block_diag(*a)
b = linalg.block_diag(*b)
c = linalg.block_diag(*c)
and constructing the resulting matrix from it by reshaping
result = linalg.block_diag(a,b,c)
result = result.reshape((5,6,6))
which does not reshape. I don't even know, if this approach would be more efficient, so I'm asking if I'm on the right track or if somebody knows a better way of constructing this block diagonal 3D matrix or if I have to stick with the for loop solution.
Edit:
Since I'm new to this platform, I don't know where to leave this (Edit or Answer?), but I want to share my final solution: The highlightet solution from panadestein worked very nice and easy, but I'm now using higher dimensional arrays, where my matrices reside in the last two dimensions. Additionally my matrices are no longer of the same dimension (mostly a mixture of 1x1, 2x2, 3x3), so I adopted V. Ayrat's solution with minor changes:
def nd_block_diag(arrs):
shapes = np.array([i.shape for i in arrs])
out = np.zeros(np.append(np.amax(shapes[:,:-2],axis=0), [shapes[:,-2].sum(), shapes[:,-1].sum()]))
r, c = 0, 0
for i, (rr, cc) in enumerate(shapes[:,-2:]):
out[..., r:r + rr, c:c + cc] = arrs[i]
r += rr
c += cc
return out
which works also with array broadcasting, if the input arrays are shaped properly (i.e. the dimensions, which are to be broadcasted are not added automatically). Thanks to pandestein and V. Ayrat for your kind and fast help, I've learned a lot about the possibilites of list comprehensions and array indexing/slicing!
block_diag also just iterate through shapes. Almost all time spend in copying data so you can do it whatever way your want for example with little change of source code of block_diag
arrs = a, b, c
shapes = np.array([i.shape for i in arrs])
out = np.zeros([shapes[0, 0], shapes[:, 1].sum(), shapes[:, 2].sum()])
r, c = 0, 0
for i, (_, rr, cc) in enumerate(shapes):
out[:, r:r + rr, c:c + cc] = arrs[i]
r += rr
c += cc
print(np.allclose(result, out))
# True
I don't think that you can escape all possible loops to solve your problem. One way that I find convenient and perhaps more efficient than your for loop is to use a list comprehension:
import numpy as np
from scipy.linalg import block_diag
# Define input matrices
a = np.ones((5, 2, 2))
b = np.ones((5, 2, 2))
c = np.ones((5, 2, 2))
# Generate block diagonal matrices
mats = np.array([a, b, c]).reshape(5, 3, 2, 2)
result = [block_diag(*bmats) for bmats in mats]
Maybe this can give you some ideas to improve your implementation.

Matrix multiplication translation from Matlab to Numpy

I'm trying to multiply some arrays together but can't seem to figure out how to do it. I'm translating some linear algebra code from MatLab and can't seem to get it to work the same in Numpy due to Matlab using column-major indexing and Python using row-major indexing.
I've managed to get the matrices to multiply, but I've not managed to get the same result as the one in Matlab.
I have three arrays:
a.shape = 40x40 in Python, 40x40 in Matlab, zeroes array
b.shape = 40x21 in Python, 21x40 in Matlab, array with < 1 float values
c.shape = 31x40 in Python, 40x31 in Matlab, array with < 1 float values
The math I'm trying to copy from Matlab is:
D = b*(a*c);
disp(size(D)); % Size of D is 21x31
When I try and do the same with NumPy:
D = b # (a # c)
It obviously doesn't work since c is 31x40 and can't multiply with A (40x40).
I've managed to get the multiplication to actually work by using:
D = np.transpose(np.transpose(b) # (a # np.transpose(c)))
but the resulting D in Numpy is different from the one in Matlab, although the dimensions are correct (31x21).
If anyone has any ideas how to do this or even if it's not possible please let me know!
nope just run it with random numbers
differences are limited to rounding errors
quick simple example to check correct matrix sizes:
import numpy as np
np.__version__
#'1.16.3'
a = np.ones([40,40])
b = np.ones([21,40])
c = np.ones([40,31])
#%%
a_mult_c = a # c
a_mult_c.shape()
# (40, 31)
#%%
D = b # a_mult_c
D.shape
# (21, 31)
for a detailed random number example load an run these numbers
https://jsonblob.com/c240c380-81a2-11e9-8287-ef9cd282f8ed
assuming you copy, paste and save it to 'matrixmult.json'
matlab:
fid = fopen('matrixmult.json', 'r');
values = jsondecode(fread(fid, '*char')'));
fclose(fid);
python:
import numpy as np
np.__version__
# '1.16.3'
import json
with open('matrixmult.json', 'r') as f: # py > 3.6
values = json.load(f)
a = np.asarray(values['a'])
b = np.asarray(values['b'])
c = np.asarray(values['c'])
D = b # (a # c)
D == np.asarray(values['D'])

Want to define an ndarray in numpy elementwise

I have 2 2d numpy arrays, A with shape (i,j) and B (i, k) where j >> k. I want to define a new 3d array C such that each element in C is the broadcasted element wise product of each column in A with the whole matrix B. In other words as a normal python loop I would do it like this
for x in range(j):
C[x] = A[:,x]*B
However j is very large in this case and it would benefit me a lot if I am able to use Numpy's functionality to maybe define an ndarray C elementwise like in my loop above.
Thank you for your help
You can use broadcasting like this:
a.T[:, :, None] * b
Example:
import numpy as np
np.random.seed(444)
i, j, k = 2, 10, 3
a = np.random.randn(i, j)
b = np.random.randn(i, k)
c = a.T[:, :, None] * b
print(c.shape)
# (10, 2, 3)
Transposing stems from the fact that you want to internally operate for each column in a, and [:, :, None] expands the dimensionality to enable broadcasting, as explained in NumPy's broadcasting rules.

Convert a 1D array to a 2D array in numpy

I want to convert a 1-dimensional array into a 2-dimensional array by specifying the number of columns in the 2D array. Something that would work like this:
> import numpy as np
> A = np.array([1,2,3,4,5,6])
> B = vec2matrix(A,ncol=2)
> B
array([[1, 2],
[3, 4],
[5, 6]])
Does numpy have a function that works like my made-up function "vec2matrix"? (I understand that you can index a 1D array like a 2D array, but that isn't an option in the code I have - I need to make this conversion.)
You want to reshape the array.
B = np.reshape(A, (-1, 2))
where -1 infers the size of the new dimension from the size of the input array.
You have two options:
If you no longer want the original shape, the easiest is just to assign a new shape to the array
a.shape = (a.size//ncols, ncols)
You can switch the a.size//ncols by -1 to compute the proper shape automatically. Make sure that a.shape[0]*a.shape[1]=a.size, else you'll run into some problem.
You can get a new array with the np.reshape function, that works mostly like the version presented above
new = np.reshape(a, (-1, ncols))
When it's possible, new will be just a view of the initial array a, meaning that the data are shared. In some cases, though, new array will be acopy instead. Note that np.reshape also accepts an optional keyword order that lets you switch from row-major C order to column-major Fortran order. np.reshape is the function version of the a.reshape method.
If you can't respect the requirement a.shape[0]*a.shape[1]=a.size, you're stuck with having to create a new array. You can use the np.resize function and mixing it with np.reshape, such as
>>> a =np.arange(9)
>>> np.resize(a, 10).reshape(5,2)
Try something like:
B = np.reshape(A,(-1,ncols))
You'll need to make sure that you can divide the number of elements in your array by ncols though. You can also play with the order in which the numbers are pulled into B using the order keyword.
If your sole purpose is to convert a 1d array X to a 2d array just do:
X = np.reshape(X,(1, X.size))
convert a 1-dimensional array into a 2-dimensional array by adding new axis.
a=np.array([10,20,30,40,50,60])
b=a[:,np.newaxis]--it will convert it to two dimension.
There is a simple way as well, we can use the reshape function in a different way:
A_reshape = A.reshape(No_of_rows, No_of_columns)
You can useflatten() from the numpy package.
import numpy as np
a = np.array([[1, 2],
[3, 4],
[5, 6]])
a_flat = a.flatten()
print(f"original array: {a} \nflattened array = {a_flat}")
Output:
original array: [[1 2]
[3 4]
[5 6]]
flattened array = [1 2 3 4 5 6]
some_array.shape = (1,)+some_array.shape
or get a new one
another_array = numpy.reshape(some_array, (1,)+some_array.shape)
This will make dimensions +1, equals to adding a bracket on the outermost
Change 1D array into 2D array without using Numpy.
l = [i for i in range(1,21)]
part = 3
new = []
start, end = 0, part
while end <= len(l):
temp = []
for i in range(start, end):
temp.append(l[i])
new.append(temp)
start += part
end += part
print("new values: ", new)
# for uneven cases
temp = []
while start < len(l):
temp.append(l[start])
start += 1
new.append(temp)
print("new values for uneven cases: ", new)
import numpy as np
array = np.arange(8)
print("Original array : \n", array)
array = np.arange(8).reshape(2, 4)
print("New array : \n", array)

Categories

Resources