Related
I have an array a as follow:
import numpy as np
a= np.array([[1, 3, 5, 7, 8, 7, 1],
[11, 13, 51, 17, 18, 17, 10]])
I want to build a list of that array with a sliding window. Here is the output that I want:
I have using the following code, however it does not provide the output which I want:
lag = 3
out = []
for i in range(2):
eachrow =[]
for col in range(a.shape[1]-lag):
X_row = []
xtmp = a[i, col:col+lag]
X_row.append(xtmp)
ytmp = a[i, col+lag]
X_row.append(ytmp)
eachrow.append(X_row)
out.append(eachrow)
Any help appreciated. Thanks.
You can use numpy.lib.stride_tricks.sliding_window_view and numpy.apply_along_axis like below:
numpy.lib.stride_tricks.sliding_window_view is New in version 1.20.0. you need update your numpy
a = np.array([[1, 3, 5, 7, 8, 7, 1],[11, 13, 51, 17, 18, 17, 10]])
b = np.lib.stride_tricks.sliding_window_view(a.ravel(),4)
def create_array(row):
return np.array([row[:3],np.array(row[-1])], dtype=object)
c = np.apply_along_axis(create_array, 1, b)
print(c)
Output:
[[array([1, 3, 5]) array(7)]
[array([3, 5, 7]) array(8)]
[array([5, 7, 8]) array(7)]
[array([7, 8, 7]) array(1)]
[array([8, 7, 1]) array(11)]
[array([ 7, 1, 11]) array(13)]
[array([ 1, 11, 13]) array(51)]
[array([11, 13, 51]) array(17)]
[array([13, 51, 17]) array(18)]
[array([51, 17, 18]) array(17)]
[array([17, 18, 17]) array(10)]]
Your code produces:
In [3]: out
Out[3]:
[[[array([1, 3, 5]), 7],
[array([3, 5, 7]), 8],
[array([5, 7, 8]), 7],
[array([7, 8, 7]), 1]],
[[array([11, 13, 51]), 17],
[array([13, 51, 17]), 18],
[array([51, 17, 18]), 17],
[array([17, 18, 17]), 10]]]
That's a list of length 2. Within that lists.
If we make an array from that - with object dtype, we get a 3d array, where some elements are arrays, and some are integers:
In [6]: arr = np.array(out, object)
In [7]: arr
Out[7]:
array([[[array([1, 3, 5]), 7],
[array([3, 5, 7]), 8],
[array([5, 7, 8]), 7],
[array([7, 8, 7]), 1]],
[[array([11, 13, 51]), 17],
[array([13, 51, 17]), 18],
[array([51, 17, 18]), 17],
[array([17, 18, 17]), 10]]], dtype=object)
In [8]: arr.shape
Out[8]: (2, 4, 2)
Change one line of your code to
X_row.append(np.array([ytmp]))
In [11]: np.array(out,object)
Out[11]:
array([[[array([1, 3, 5]), array([7])],
[array([3, 5, 7]), array([8])],
[array([5, 7, 8]), array([7])],
[array([7, 8, 7]), array([1])]],
[[array([11, 13, 51]), array([17])],
[array([13, 51, 17]), array([18])],
[array([51, 17, 18]), array([17])],
[array([17, 18, 17]), array([10])]]], dtype=object)
or displayed with the str/print array formatting:
In [12]: print(_)
[[[array([1, 3, 5]) array([7])]
[array([3, 5, 7]) array([8])]
[array([5, 7, 8]) array([7])]
[array([7, 8, 7]) array([1])]]
[[array([11, 13, 51]) array([17])]
[array([13, 51, 17]) array([18])]
[array([51, 17, 18]) array([17])]
[array([17, 18, 17]) array([10])]]]
We could reshape that to a (8,2) array (still object dtype):
In [14]: print(Out[11].reshape(-1,2))
[[array([1, 3, 5]) array([7])]
[array([3, 5, 7]) array([8])]
[array([5, 7, 8]) array([7])]
[array([7, 8, 7]) array([1])]
[array([11, 13, 51]) array([17])]
[array([13, 51, 17]) array([18])]
[array([51, 17, 18]) array([17])]
[array([17, 18, 17]) array([10])]]
Since the inner most arrays have a mixed size - some 3 some 1, the result can only be object dtype - or list of lists. That's isn't optimal for array calculations.
Commas are part of the display, along with [] and words like array. Together they give us clues as to the underlying objects, whether they are lists or arrays. Equally important are the shape and dtype (if the object is an array) or length if a list.
===
Another answer uses a striding_tricks function. Here's that method in more detail. While x is a view, slicing and reshaping will make copies, so it's hard to say whether this is any faster. For this small example I bet your code is faster, but for larger case it might not be.
In [16]: np.lib.stride_tricks.sliding_window_view(a,(1,4))
Out[16]:
array([[[[ 1, 3, 5, 7]],
[[ 3, 5, 7, 8]],
[[ 5, 7, 8, 7]],
[[ 7, 8, 7, 1]]],
[[[11, 13, 51, 17]],
[[13, 51, 17, 18]],
[[51, 17, 18, 17]],
[[17, 18, 17, 10]]]])
In [17]: x = np.lib.stride_tricks.sliding_window_view(a,(1,4))
In [18]: x.shape
Out[18]: (2, 4, 1, 4)
That's a 4d view of the original 1d array.
Your size 3 'arrays' can be sliced from that:
In [19]: x[:,:,0,:3]
Out[19]:
array([[[ 1, 3, 5],
[ 3, 5, 7],
[ 5, 7, 8],
[ 7, 8, 7]],
[[11, 13, 51],
[13, 51, 17],
[51, 17, 18],
[17, 18, 17]]])
In [20]: x[:,:,0,:3].reshape(-1,3)
Out[20]:
array([[ 1, 3, 5],
[ 3, 5, 7],
[ 5, 7, 8],
[ 7, 8, 7],
[11, 13, 51],
[13, 51, 17],
[51, 17, 18],
[17, 18, 17]])
and the 1 element column:
In [21]: x[:,:,0,-1].reshape(-1,1)
Out[21]:
array([[ 7],
[ 8],
[ 7],
[ 1],
[17],
[18],
[17],
[10]])
These 2 arrays may be more useful than your object out.
The arrays shown in [14] could be split into 2 similar arrays:
In [27]: np.stack(arr.reshape(-1,2)[:,0])
Out[27]:
array([[ 1, 3, 5],
[ 3, 5, 7],
[ 5, 7, 8],
[ 7, 8, 7],
[11, 13, 51],
[13, 51, 17],
[51, 17, 18],
[17, 18, 17]])
In [28]: arr.reshape(-1,2)[:,1].astype(int)
Out[28]: array([ 7, 8, 7, 1, 17, 18, 17, 10])
There are two issues I see:
The last element in the window isn't enclosed in an np.array.
Then, a quick fix would be to change this line:
X_row.append(ytmp)
to
X_row.append(np.array([ytmp]))
which produces the desired output.
The result is two dimensions, since you create a separate sublist for each row in the array, and then append that sublist to the result. To resolve, change:
out.append(eachrow)
to
out.extend(eachrow)
You can use numpy.lib.stride_tricks.sliding_window_view for a fast, vectorized solution:
x = np.lib.stride_tricks.sliding_window_view(a, (1,3))[:, :-1]
x.shape = (*x.shape[:2], *x.shape[3:])
y = a[:, -x.shape[1]:, None]
Output:
>>> x
array([[[ 1, 3, 5],
[ 3, 5, 7],
[ 5, 7, 8],
[ 7, 8, 7]],
[[11, 13, 51],
[13, 51, 17],
[51, 17, 18],
[17, 18, 17]]])
>>> y
array([[[ 7],
[ 8],
[ 7],
[ 1]],
[[17],
[18],
[17],
[10]]])
Now, just use zip + list:
out = [list(zip(x[i], y[i])) for i in range(len(y))]
Output:
>>> out
[[(array([1, 3, 5]), array([7])),
(array([3, 5, 7]), array([8])),
(array([5, 7, 8]), array([7])),
(array([7, 8, 7]), array([1]))],
[(array([11, 13, 51]), array([17])),
(array([13, 51, 17]), array([18])),
(array([51, 17, 18]), array([17])),
(array([17, 18, 17]), array([10]))]]
I have some np arrays. I want to concatenate them as objects in an np array.
coords1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
coords2 = np.array([[13, 14, 15, 16], [17, 18, 19, 20]])
I want to obtain coordsAll
coordsAll = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20]]]
This is my code:
coords1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
coords2 = np.array([[13, 14, 15, 16], [17, 18, 19, 20]])
coordsAll = np.empty(np.array(np.array((0, 4), int)), object)
coordsAll = np.append (coordsAll, coords1, axis=0)
coordsAll = np.append(coordsAll, coords2, axis=0)
coordsAll is now
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20]]
but i want two objects in my output array like
[[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20]]]
Many thanks.
Maybe something like that:
coordsAll = np.array([coords2, coords1], dtype=object)
print(coordsAll)
print(coordsAll.dtype)
In [457]: coordsAll
Out[457]:
array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
[17, 18, 19, 20]], dtype=object)
Your repeated use of np.append joins a (0,4) and (3,4) to make a (3,4), and then adds a (2,4), resulting in a (5,4). Specifying object dtype doesn't change that behavior. You might as well do:
In [458]: np.concatenate((coords1, coords2), axis=0)
Out[458]:
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16],
[17, 18, 19, 20]])
Where concatenate takes a whole list of arrays. Repeated calls in a loop is inefficient. Plus you have to make that weird (0,4) array to start with. Modeling array operations on list ones is not a good idea.
The safest way to make an object array of a desired size, is to initial it, and then fill:
In [459]: res = np.empty(2, object)
In [460]: res
Out[460]: array([None, None], dtype=object)
In [461]: res[0] = coords1
In [462]: res[1] = coords2
In [463]: res
Out[463]:
array([array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]]), array([[13, 14, 15, 16],
[17, 18, 19, 20]])], dtype=object)
np.array with object dtype also works in this case, but may fail with other combinations of shapes:
In [464]: np.array((coords1, coords2), object)
Out[464]:
array([array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]]), array([[13, 14, 15, 16],
[17, 18, 19, 20]])], dtype=object)
arrays of the same shape produces a 3d array:
In [465]: np.array((coords1, coords1), object)
Out[465]:
array([[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]],
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]], dtype=object)
and (4,3) with (4,2) produces an error:
In [466]: np.array((coords1.T, coords2.T), object)
Traceback (most recent call last):
File "<ipython-input-466-dff6d2a13fa4>", line 1, in <module>
np.array((coords1.T, coords2.T), object)
ValueError: could not broadcast input array from shape (4,3) into shape (4,)
Keep in mind that your desired array is not a "normal" ndarray. It's much closer to the simple list [coords1, coords2], with few of multidimensional advantages of Out[458].
I have a NumPy ndarray A of size (k,n,m) of int, representing k images each of size nxm pixels.
I would like to convert it into a dtype=object ndarray B of size (k,) containing each of the individual images as ndarrays of size (n,m).
I can do it with a for-loop (below), but is there a more elegant/straightforward way?
A = np.arange(2*3*4).reshape(2,3,4)
B = np.empty(A.shape[0],dtype=object)
for i in range(0,A.shape[0]):
B[i] = A[i]
print(B)
array([array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]), array([[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])], dtype=object)
Your arrays:
In [37]: A = np.arange(2*3*4).reshape(2,3,4)
...:
...: B = np.empty(A.shape[0],dtype=object)
...: for i in range(0,A.shape[0]):
...: B[i] = A[i]
...:
In [38]: B
Out[38]:
array([array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]), array([[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])], dtype=object)
Alternate way of assigning A to B. Shorter, but not necessarily faster.
In [39]: B[:]=list(A)
In [40]: B
Out[40]:
array([array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]), array([[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])], dtype=object)
Direct assignment does not work; it has to be a list of arrays, not an array:
In [41]: B[:]=A
Traceback (most recent call last):
File "<ipython-input-41-b3ca91787565>", line 1, in <module>
B[:]=A
ValueError: could not broadcast input array from shape (2,3,4) into shape (2,)
The other answer does not work:
In [42]: np.array([*A], dtype=object)
Out[42]:
array([[[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]], dtype=object)
You could use unpacking instead to get cleaner code:
B = np.array([*A], dtype=object)
EDIT: This does not work as the inner elements also gets turned into object type.
I have a huge (N*20) matrix where every 5 rows is a valid sample, ie. every (5*20) matrix. I'm trying to reshape it into a (N/5,1,20,5) matrix where the dimension 20 is kept unchanged. I could do it in tensroflow using keep_dim, but how can I achieve this in numpy?
Thanks in advance.
Reshape and then swap the axes around:
arr1 = arr.reshape(N/5,5,1,20)
arr2 = arr1.transpose(0,2,3,1)
for example
In [476]: arr = np.arange(24).reshape(6,4)
In [477]: arr
Out[477]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
In [478]: arr1 = arr.reshape(2,3,1,4)
In [479]: arr2 = arr1.transpose(0,2,3,1)
In [480]: arr2.shape
Out[480]: (2, 1, 4, 3)
In [482]: arr2
Out[482]:
array([[[[ 0, 4, 8],
[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11]]],
[[[12, 16, 20],
[13, 17, 21],
[14, 18, 22],
[15, 19, 23]]]])
I have an 2D-array a with shape (k,n) and I want to 'multiply' it with an 1D-array b of shape (m,):
a = np.array([[2, 8],
[4, 7],
[1, 2],
[5, 2],
[7, 4]])
b = np.array([3, 5, 5])
As a result of the 'multiplication' I'm looking for:
array([[[2*3,2*5,2*5],[8*3,8*5,8*5]],
[[4*3,4*5,4*5],[7*3,7*5,7*5]],
[[1*3,1*5,1*5], ..... ]],
................. ]]])
= array([[[ 6, 10, 10],
[24, 40, 40]],
[[12, 20, 20],
[21, 35, 35]],
[[ 3, 5, 5],
[ ........ ]],
....... ]]])
I could solve it with a loop of course, but I'm looking for a fast vectorized way of doing it.
Extend a to a 3D array case by adding a new axis at the end with np.newaxis/None and then do elementwise multiplication with b, bringing in broadcasting for a vectorized solution, like so -
b*a[...,None]
Sample run -
In [19]: a
Out[19]:
array([[2, 8],
[4, 7],
[1, 2],
[5, 2],
[7, 4]])
In [20]: b
Out[20]: array([3, 5, 5])
In [21]: b*a[...,None]
Out[21]:
array([[[ 6, 10, 10],
[24, 40, 40]],
[[12, 20, 20],
[21, 35, 35]],
[[ 3, 5, 5],
[ 6, 10, 10]],
[[15, 25, 25],
[ 6, 10, 10]],
[[21, 35, 35],
[12, 20, 20]]])