Numpy array with arrays of different size inside - python

I want to create a 3D np.array named output of varying size. An array of size (5,a,b); with a and b varying (b decreasing):
(a,b) = (1000,20)
(a,b) = (1000,19)
(a,b) = (1000,18)
(a,b) = (1000,17)
(a,b) = (1000,16)
I could create an array of arrays in order to do so, but later on I want to get the first column of all the arrays (without a loop) then I cannot use:
output[:,:,0]
Concatenating them wont work also, it asks for the same size of the arrays...
Any alternatives to be able to have a varying single array instead of an array of arrays?
Thanks!

Like #Divakar said, create an empty array with type object and assign the different sized arrays to their respective indices.
import numpy as np
arrs = [np.ones((5, i, 10 - i)) for i in range(10)]
arrs[0].shape
(5, 0, 10)
arrs[1].shape
(5, 1, 9)
out = np.emtpy(len(arrs), dtype=object)
out[:] = arrs
out[0].shape
(5, 0, 10)
out[1].shape
(5, 1, 9)

Maybe you could make a list and add this 5 arrays.

Related

Changing values of a 3D array based on 2D coordinates (Python)

I have 2 arrays. Call them 'A' and 'B'.
The shape of array 'A' is (10,10,3), and the shape of array 'B' is (10,10).
Now, I have acquired the coordinates of certain elements of array 'B' as a list of tuples. Let's call the list 'TupleList'.
I want to now make the values of all elements in array 'A' equal to 0, except for those elements present at the coordinates in 'TupleList'.
Imagine the arrays are image arrays. Where A being an RGB image has the 3rd dimension.
How can I do so?
I am having trouble doing this because of the extra 3rd dimension that array 'A' has. Otherwise, it is quite straightforward with the use of np.where(), given that I know the limited number of values that array 'B' can take.
Here is a solution by transposing the indices list into list of indices for the first dimension and list of indices for the second dimension:
import numpy as np
nrows, ncols = 5, 5
arr = np.arange(nrows * ncols * 3, dtype=float).reshape(nrows, ncols, 3)
idxs = [(0, 1), (1, 3), (3, 2), (4, 2)]
idxs_dim0, idxs_dim1 = zip(*idxs)
res = np.zeros(arr.shape)
res[idxs_dim0, idxs_dim1] = arr[idxs_dim0, idxs_dim1]
Checking the result:
from itertools import product
for idx_dim0, idx_dim1 in product(range(nrows), range(ncols)):
value = res[idx_dim0, idx_dim1]
if (idx_dim0, idx_dim1) in idxs:
assert np.all(value == arr[idx_dim0, idx_dim1])
else:
assert np.all(value == (0, 0, 0))

numpy's transpose method can't convert 1D row ndarray to a column one [duplicate]

This question already has answers here:
Transposing a 1D NumPy array
(15 answers)
Closed 3 years ago.
Let's consider a as an 1D row/horizontal array:
import numpy as np
N = 10
a = np.arange(N) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
a.shape # (10,)
now I want to have b a 1D column/vertical array transposed of a:
b = a.transpose() # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
b.shape # (10,)
but the .transpose() method returns an identical ndarray whith the exact same shape!
What I expected to see was
np.array([[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]])
which can be achieved by
c = a.reshape(a.shape[0], 1) # or c = a; c.shape = (c.shape[0], 1)
c.shape # (10, 1)
and to my surprise, it has a shape of (10, 1) instead of (1, 10).
In Octave/Scilab I could do:
N = 10
b = 0:(N-1)
a = b'
size(b) % ans = 1 10
size(a) % ans = 10 1
I understand that numpy ndarrays are not matrices (as discussed here), but the behavior of the numpy's transpose function just doesn't make sense to me! I would appreciate it if you could help me understand how this behavior makes sense and what am I missing here.
P.S. So what I have understood so far is that b = a.transpose() is the equivalent of b = a; b.shape = b.shape[::-1] which if you had a "2D array" of (N, 1) would return a (1, N) shaped array, as you would expect from a transpose operator. However, numpy seems to treat the "1D array" of (N,) as a 0D scalar. I think they should have named this method something else, as this is very misleading/confusing IMHO.
To understand the numpy array better, you should take a look at this review paper: The NumPy array: a structure for efficient numerical computation
In short, numpy ndarrays have this attribute called the stride, which is
the number of bytes to skip in memory to proceed to the next element.
For a (10, 10) array of bytes, for example, the strides may be (10,
1), in other words: proceed one byte to get to the next column and ten
bytes to locate the next row.
For your ndarray a, a.stride = (8,), which shows that it is only 1 dimensional, and that to get to the next element on this single dimension, you need to advance 8 bytes in memory (each int is 64-bit).
Strides are useful for representing transposes:
By modifying strides, for example, an array can be transposed or
reshaped at zero cost (no memory needs to be copied).
So if there was a 2-dimensional ndarray, say b = np.ones((3,5)) for example, then b.strides = (40, 8), while b.transpose().strides = (8, 40). So as you see a transposed 2D-ndarray is simply the exact same array, whose strides have been reordered. And since your 1D ndarray has only 1 dimension, swapping the the values of its strides (i.e. taking its transpose), doesn't do anything.
As you already mentioned that numpy array are not matrix. The defination of transpose function is like below
Permute the dimensions of an array.
Which means that numpy's transpose method will move data from one dimension to another. As 1D array has only one dimension there is no other dimension to move the data t0. So you need add a dimension before transpose has any effect. This behavior make sense also to be consistent with higher dimensional array (3D, 4D ...) array.
There is a clean way to achive what you want
N = 10
a = np.arange(N)
a[ :, np.newaxis]

How to fuse two axis of a n-dimentional array in Python

Instead of a n-dimentional array, let's take a 3D array to illustrate my question :
>>> import numpy as np
>>> arr = np.ones(24).reshape(2, 3, 4)
So I have an array of shape (2, 3, 4). I would like to concatenate/fuse the 2nd and 3rd axis together to get an array of the shape (2, 12).
Wrongly, thought I could have done it easily with np.concatenate :
>>> np.concatenate(arr, axis=1).shape
(3, 8)
I found a way to do it by a combination of np.rollaxis and np.concatenate but it is increasingly ugly as the array goes up in dimension:
>>> np.rollaxis(np.concatenate(np.rollaxis(arr, 0, 3), axis=0), 0, 2).shape
(2, 12)
Is there any simple way to accomplish this? It seems very trivial, so there must exist some function, but I cannot seem to find it.
EDIT : Indeed I could use np.reshape, which means to compute the dimensions of the axis first. Is it possible without accessing/computing the shape beforehand?
On recent python versions you can do:
anew = a.reshape(*a.shape[:k], -1, *a.shape[k+2:])
I recommend against directly assigning to .shape since it doesn't work on sufficiently noncontiguous arrays.
Let's say that you have n dimensions in your array and that you want to fuse adjacent axis i and i+1:
shape = a.shape
new_shape = list(shape[:i]) + [-1] + list(shape[i+2:])
a.shape = new_shape

Iteratively appending ndarray arrays using numpy in Python

I am trying to figure out how to iteratively append 2D arrays to generate a singular larger array. On each iteration a 16x200 ndarray is generated as seen below:
For each iteration a new 16x200 array is generated, I would like to 'append' this to the previously generated array for a total of N iterations. For example for two iterations the first generated array would be 16x200 and for the second iteration the newly generated 16x200 array would be appended to the first creating a 16x400 sized array.
train = np.array([])
for i in [1, 2, 1, 2]:
spike_count = [0, 0, 0, 0]
img = cv2.imread("images/" + str(i) + ".png", 0) # Read the associated image to be classified
k = np.array(temporallyEncode(img, 200, 4))
# Somehow append k to train on each iteration
In the case of the above embedded code the loop iterates 4 times so the final train array is expected to be 16x800 in size. Any help would be greatly appreciated, I have drawn a blank on how to successfully accomplish this. The code below is a general case:
import numpy as np
totalArray = np.array([])
for i in range(1,3):
arrayToAppend = totalArray = np.zeros((4, 200))
# Append arrayToAppend to totalArray somehow
While it is possible to perform a concatenate (or one of the 'stack' variants) at each iteration, it is generally faster to accumulate the arrays in a list, and perform the concatenate once. List append is simpler and faster.
alist = []
for i in range(0,3):
arrayToAppend = totalArray = np.zeros((4, 200))
alist.append(arrayToAppend)
arr = np.concatenate(alist, axis=1) # to get (4,600)
# hstack does the same thing
# vstack is the same, but with axis=0 # (12,200)
# stack creates new dimension, # (3,4,200), (4,3,200) etc
Try using numpy hstack. From the documention, hstack takes a sequence of arrays and stack them horizontally to make a single array.
For example:
import numpy as np
x = np.zeros((16, 200))
y = x.copy()
for i in xrange(5):
y = np.hstack([y, x])
print y.shape
Gives:
(16, 400)
(16, 600)
(16, 800)
(16, 1000)
(16, 1200)

How to do dyadics-like operations in numpy

I have two 2-D arrays A and B. I want to get a 3-D array C, whose relation with A and B is:
C_mnl=A_mn*B_ml
How can I do this elegantly in numpy?
numpy.einsum can do that:
a = np.arange(6).reshape(3,2) # a.shape = (3, 2)
b = np.arange(12).reshape(3,4) # b.shape = (3, 4)
c = np.einsum('mn,ml->mnl', a, b) # c.shape = (3, 2, 4)
You can also use broadcasting -
C = A[...,None]*B[:,None,:]
Explanation
A[...,None] adds a new axis as the last axis with None (an equivalent for np.newaxis) pushing all existing dimensions to the front. Thus, this would be same as A[:,:,None].
Similarly with B[:,None,:], it adds a new axis between the existing dimensions.
With steps 1 and 2, we have the axes of the input arrays aligned and thus when operated with elementwise-multiplication would result in the desired output of shape (m,n,l) with broadcasting.

Categories