Programmatically cropping an array along all its axes in Numpy - python

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)

Related

sum product of 2d with 3d numpy arrays plus a scalar computation

just asked a basic question earlier on dot product of two 2d arrays with hopes that I can then figure out how to expand the logic to the following question where one matrix is actually in 3d and then further multiplied by a 1d scalar vector, with no success... sorry for the back-to-back questions, numpy looks much more complicated that I thought..
I have the following 3 arrays
a = np.array([[1, 2, 3], [3, 4, 5]])
b = np.array([[[1, 0, 1], [1, 1, 0], [0, 1, 1]], [[1, 1, 1], [0, 1, 0], [0, 0, 1]]])
c = np.array([1, 2, 3])
I'd like to do the following computation. I am just going to type out the formula directly as I am not sure how to properly describe it in words (if someone can enlighten me on this as well I would be interested to know!)...
[[(1*1 + 0*2 + 1*3)/1, (1*1 + 1*2 + 0*3)/2, (0*1, 1*2, 1*3)/3],
[(1*3 + 1*4 + 1*5)/1, (0*3 + 1*4 + 0*5)/2, (0*3, 0*4, 1*5)/3]]
>>> [[4, 1.5, 1.67], [12, 2, 1.67]]
it probably have to do with how to use the axis arg but I can't figure out quite yet... thanks much again!!
Correct answer: np.sum((a[:,None,:] * b), axis=2) / c
Process step by step visually:
Additional comments
a[:,None,:] inserts an extra dimension in the middle of size 1. a.shape is (2, 3) and a[:,None,:] is (2, 1, 3). a[None,:,:] and [a[:,:,None] does the same, you can check it with a shape parameter.
One of approaches of understanding this problem is visual. All the pictures demonstrate how three dimensions corresponds to axis=0, axis=1, axis=2. So if you had an array of shape = (2, 1, 3), its visualisation would be a cuboid of height = 2, width = 1 and lenght = 3. For example, you can see visually how a[:,:,None] and b are broadcasted into a new array a[:,:,None] * b.
There's also a symbolic (formal) way to see it. Only arrays of balanced shapes could be broadcasted. So arrays of shapes (2, 3) and (2, 1, 3) can't be broadcasted unlikely to arrays of shapes (2, 3, 3) and (2, 1, 3). But, arrays of shapes (4, 3) and (3,) can be broadcasted. I mean, there are mathematical rules which defines whether arrays are broadcastable.
That may not be what you were looking for exactly (as it reshapes the numpy array using a list, which is not very efficient), but it seems to work :
d = np.array([[row]*3 for row in a]) #reshape np.array to 3d
print((d*b).sum(axis=2)/c)

use `numpy.take` to randomly select 2d points

Problem Setup:
points - 2D numpy.array of length N.
centroids - 2D numpy.array that I get as an output from K-Means algorithm, of length k < N.
as a centroid initialization routine for an MLE algorithm, I want to assign each point in points a random centroid from centroids.
Required Output:
A numpy.array of shape (N, 2), of randomly chosen 2D points from centroids
My Efforts:
I've tried using the numpy.take with the numpy.random.choice as shown in Code 1, but it doesn't return the desired output.
Code 1:
import numpy as np
a = np.random.randint(1, 10, 10).reshape((5, 2))
idx = np.random.choice(5, 20)
np.take(a, idx)
Out: array([6, 2, 3, 3, 8, 2, 5, 2, 6, 3, 3, 8, 6, 6, 6, 6, 8, 2, 6, 5])
From numpy.take documentation page I've learned that it chooses items from flattened array, which is not what I need.
I'd appreciate any ideas on how to accomplish this task. Thanks in advance for any help.
One way is sampling the indexes, and then use that to index the first dimension of centroids:
idx = np.random.choice(np.arange(len(centroids)), size=len(a))
out = centroids[idx]
A similar to #Quang Hoang's answer, but a bit more intuitive in my opinion, will be :
a = np.random.randint(1, 10, 10).reshape((5, 2))
n_sampled_points = 20
a[np.random.randint(0, a.shape[0], n_sampled_points)]
Cheers.

Need help converting Matlab's bsxfun to numpy

I'm trying to convert a piece of MATLAB code, and this is a line I'm struggling with:
f = 0
wlab = reshape(bsxfun(#times,cat(3,1-f,f/2,f/2),lab),[],3)
I've come up with
wlab = lab*(np.concatenate((3,1-f,f/2,f/2)))
How do I reshape it now?
Not going to do it for your code, but more as a general knowledge:
bsxfun is a function that fills a gap in MATLAB that python doesn't need to fill: broadcasting.
Broadcasting is a thing where if a matrix that is being multiplied/added/whatever similar is not the same size as the other one being used, the matrix will be repeated.
So in python, if you have a 3D matrix A and you want to multiply every 2D slice of it with a matrix B that is 2D, you dont need anything else, python will broadcast B for you, it will repeat the matrix again and again. A*B will suffice. However, in MATLAB that will raise an error Matrix dimension mismatch. To overcome that, you'd use bsxfun as bsxfun(#times,A,B) and this will broadcast (repeat) B over the 3rd dimension of A.
This means that converting bsxfun to python generally requires nothing.
MATLAB
reshape(x,[],3)
is the equivalent of numpy
np.reshape(x,(-1,3))
the [] and -1 are place holders for 'fill in the correct shape here'.
===============
I just tried the MATLAB expression is Octave - it's on a different machine, so I'll just summarize the action.
For lab=1:6 (6 elements) the bsxfun produces a (1,6,3) matrix; the reshape turns it into (6,3), i.e. just removes the first dimension. The cat produces a (1,1,3) matrix.
np.reshape(np.array([1-f,f/2,f/2])[None,None,:]*lab[None,:,None],(-1,3))
For lab with shape (n,m), the bsxfun produces a (n,m,3) matrix; the reshape would make it (n*m,3)
So for a 2d lab, the numpy needs to be
np.array([1-f,f/2,f/2])[None,None,:]*lab[:,:,None]
(In MATLAB the lab will always be 2d (or larger), so this 2nd case it closer to its action even if n is 1).
=======================
np.array([1-f,f/2,f/2])*lab[...,None]
would handle any shaped lab
If I make the Octave lab (4,2,3), the `bsxfun is also (4,2,3)
The matching numpy expression would be
In [94]: (np.array([1-f,f/2,f/2])*lab).shape
Out[94]: (4, 2, 3)
numpy adds dimensions to the start of the (3,) array to match the dimensions of lab, effectively
(np.array([1-f,f/2,f/2])[None,None,:]*lab) # for 3d lab
If f=0, then the array is [1,0,0], so this has the effect of zeroing values on the last dimension of lab. In effect, changing the 'color'.
It is equivalent to
import numpy as np
wlab = np.kron([1-f,f/2,f/2],lab.reshape(-1,1))
In Python, if you use numpy you do not need to do any broadcasting, as this is done automatically for you.
For instance, looking at the following code should make it clearer:
>>> import numpy as np
>>> a = np.array([[1, 2, 3], [3, 4, 5], [6, 7, 8], [9, 10, 100]])
>>> b = np.array([1, 2, 3])
>>>
>>> a
array([[ 1, 2, 3],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 100]])
>>> b
array([1, 2, 3])
>>>
>>> a - b
array([[ 0, 0, 0],
[ 2, 2, 2],
[ 5, 5, 5],
[ 8, 8, 97]])
>>>

Delete Dimension of mutlidimensional array

i have an array of shape
(512, 240, 1, 3, 3)
How can I get red of the last dimension. Should work with
np.delete
but cant figure out how exactly. all the examples are in 2D...
I think I misformulated the question. What I looked for was
A = A[:,:,:,0]
Sorry
I believe (512, 240, 1, 3, 3) is a tuple (data you're working with) and not a shape of your array. To remove the last dimension (3 in your case) with numpy.delete you can do the following:
>>> import numpy as np
>>> a=np.array((512, 240, 1, 3, 3))
>>> a=np.delete(a,4)
>>> a
array([512, 240, 1, 3])
Remember that numpy.delete returns a new array and the original one stays unchanged. That's why I did a=np.delete(...).
I'm not exactly sure what you mean by delete the last dimension, but if you want to merge the two last dimensions, you can use np.reshape(yourArray, (512, 240, 1, 3*3))

Creating numpy array of matrices

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)

Categories

Resources