view_as_windows on 4d array - python

Given an ndarray of shape (batch_size, w, h, c), and a patch size (p, p), I want to extract patches from each 3D matrix (i.e. shape (p, p, c). No patches will overlap, so the stride can be thought of as p.
This should return an array with (batch_size * p * p, p, p, c)
Using skimage.view_as_windows here is a minimal example
import numpy as np
import skimage
a = np.arange(8*8*2).reshape((8, 8, 2))
b = a * 2
c = np.concatenate((a[np.newaxis, :, :, :], b[np.newaxis, :, :, :]), axis = 0)
d = skimage.util.view_as_windows(c, 2, step = 2).reshape((8*2*2, 2, 2, 2))
However, only the alternate values are what I expect:
d[0]
Out[183]:
array([[[ 0, 1],
[ 2, 3]],
[[16, 17],
[18, 19]]])
d[1]
Out[184]:
array([[[ 0, 2],
[ 4, 6]],
[[32, 34],
[36, 38]]])
d[2]
Out[185]:
array([[[ 4, 5],
[ 6, 7]],
[[20, 21],
[22, 23]]])
d[3]
Out[186]:
array([[[ 8, 10],
[12, 14]],
[[40, 42],
[44, 46]]])
d[4]
Out[187]:
array([[[ 8, 9],
[10, 11]],
[[24, 25],
[26, 27]]])
Thus, d[::2] is close to my solution but half the values are lost
I am not sure if the problem is the window size or the step, or even if my problem is possible using view_as_windows, so I am open to any efficient suggestion.

First, I think you mean to return a volume of shape (batch_size * w/p * h/p, p, p, c)? i.e., if the patches are non-overlapping, then the product of the dimensions should be the same pre- and post-patching.
Having gotten that out of the way, here's my attempt. I'm changing the batch size and channel dimensions to make it clearer which is which.
import numpy as np
from skimage import util
batch = np.arange(4*8*8*3).reshape((4, 8, 8, 3))
blocked = util.view_as_blocks((1, 2, 2, 3))
patches = blocked.reshape((64, 2, 2, 3))
print(patches[0].transpose((2, 0, 1)))
print(patches[1].transpose((2, 0, 1)))
which gives:
[[[0 1]
[8 9]]
[[0 1]
[8 9]]
[[0 1]
[8 9]]]
and
[[[ 2 3]
[10 11]]
[[ 2 3]
[10 11]]
[[ 2 3]
[10 11]]]
Unfortunately, the reshape triggers a copy. I'm not sure whether there is a way to avoid it, but hopefully this is not your main computational/memory concern.

Related

caculate 3-D array numpy value without loops base on exist 3-D array numpy

i have a 3D-np.array s like this
s = np.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],
[24, 25, 26]]], dtype=float)
call (x, y, z) id coordinate of a element of array, how could i use numpy to caculate s[x, y, z] /= np.sum(s[:, :, z])
ex:
x, y, z = s.shape
s1 = s.copy()
for i in range(x):
for j in range(y):
for k in range(z):
s1[i, j, k] = s[i, j, k] / np.sum(s[:, :, k])
# I use s1 cause I scare s will change after every loop
# and np.sum(s[:,:,k]) is not a const
# pseudo-code example:
# s[0, 0, 1] = 1
# sum[:, :, 1] = 117 # sum of 2nd column
# then
# s[0,0,1] = 1/117
# repeat with x*y*z-1 point remain
i has try to use np.fromfunction but if run too slow. my code ex:
def f(x, y, z):
result = s[x, y, z] / np.sum(s[:, :, z])
return result
s1 = np.fromfunction(np.vectorize(f), (a, b, c), dtype='int')
# a, b, c is shape of the array
Can I complete this with faster ways without for loop?
What about
s/s.sum(axis=(0, 1), keepdims=True)
or equivalently
s/np.sum(s, axis=(0, 1), keepdims=True)
Argument axis specifies the dimensions the sum is performed along. keepdims allows the result of the summation to keep its original dimensionality – 3 in the current case – which makes the division broadcast-gnostique.
If you just want to divide all elements of the array by some value, it's enough to call the division without indexing the array.
test = np.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],
[24, 25, 26]]])
print(test/np.sum(test[:,:,1]))
Or if you want to embed it in a function:
def array_divide(inputArr):
return inputArr/np.sum(inputArr[:,:,1])

How to multiply a tensor with a vector?

I have 2 tensors
a = torch.tensor([1,2])
b = torch.tensor([[[10,20],
[30,40]],
[[1,2],
[3,4]]])
and I would like to combine them in such a way that
a ? b = tensor([[[10,20],
[30,40]],
[[ 2, 4],
[ 6, 8]]])
(and then sum over the 0th dimension, in the end I want to do a weighted sum)
I've tried:
""" no idea how to interpret that """
a # b
tensor([[ 70, 100],
[ 7, 10]])
b # a
tensor([[ 50, 110],
[ 5, 11]])
for i in range(b.size()[0]): # works but I don't think this will work with autograd
b[i] *= a[i]
a * b # multiplies right side by 2
tensor([[[10, 40],
[30, 80]],
[[ 1, 4],
[ 3, 8]]])
a.unsqueeze(1) # multiplies bottom side by 2
tensor([[[10, 20],
[60, 80]],
[[ 1, 2],
[ 6, 8]]])
a.unsqueeze(2) * b # dimension out of range
This should workc = a.unsqueeze(1).unsqueeze(1) * b
You can also try below code:
a = torch.tensor([1,2])
b = torch.tensor([[[10,20],
[30,40]],
[[1,2],
[3,4]]])
print((a.view(-1, 1)*torch.flatten(b, 1)).view(b.shape))
output:
tensor([[[10, 20],
[30, 40]],
[[ 2, 4],
[ 6, 8]]])
Here, we are basically carrying out below steps:
Reshaping a to a 2d tensor of size [a.shape[0],1], i.e. [2, 1] in above case.
Then, we are using torch.flatten() to flatten tensor b starting from the first dimension(i.e. start_dim=1). Here, end_dim=-1 by default. Resultant size is [2, 4].
Performing element-wise multiplication.
Finally, reshaping the result to shape same as original tensor b, i.e [2, 2, 2].
Interesting -- I tried a few different broadcasting tricks and didn't see any obvious wins, so the simple version:
b[0] *= a[0]
b[1] *= a[1]
c = b

Multiplying NumPy arrays by scalars

I have a NumPy array of shape (2,76020,2). Basically it is made of two columns containing 76020 rows each, and each row has two entries.
I want to multiply each column by a different weight, say column 1 by 3 and column 2 by 5. For example:
m =
[3,4][5,8]
[1,2][2,2]
a = [3,5]
I want:
[9,12][25,40]
[3,6][10,10]
I thought I could just multiply m*a, but that gives me instead:
[9,20][15,40]
[3,10][6,10]
How can I write this multiplication?
It's a problem of broadcasting: you must align the dimensions to multiply, here the second:
m = array(
[[[3,4],[5,8]],
[[1,2],[2,2]]])
a = array([3,5])
print(a[None,:,None].shape, m*a[None,:,None])
"""
(1, 2, 1)
[[[ 9 12]
[25 40]]
[[ 3 6]
[10 10]]]
"""
As #B.M. says, this is a 'array broadcasting' issue. (The idea behind his answer is correct, but I think his and the OP's dimensions aren't matching up correctly.)
>>> m = np.array([[[3,4],[5,8]],[[1,2],[2,2]]])
>>> print(m)
[[[3 4]
[5 8]]
[[1 2]
[2 2]]]
>>> print(m.shape)
(2, 2, 2)
>>> a = np.array([3,5])
>>> print(a.shape)
(2,)
We need the shapes of m and a to match, so we have to 'broadcast' a to the correct shape:
>>> print(a[:, np.newaxis, np.newaxis].shape)
(2, 1, 1)
>>> b = a[:, np.newaxis, np.newaxis] * m
>>> print(b)
[[[ 9 12]
[15 24]]
[[ 5 10]
[10 10]]]
In this way the first dimension of a is preserved, and maps to each element of the first dimension of m. But there are also two new dimensions ('axes') created to 'broadcast' into the other two dimensions of m.
Note: np.newaxis is (literally) None, they have the same effect. The former is more readable to understand what's happening. Additionally, just in terms of standard terminology, the first dimension (axis) is generally referred to as the 'rows', and the second axis the 'columns'.
Your description is ambiguous
Basically it is made of two columns containing 76020 rows each, and each row has two entries.
In (2,76020,2), which 2 is columns, and which is entries?
I believe your m is (that display is also ambiguous)
In [8]: m
Out[8]:
array([[[3, 4],
[5, 8]],
[[1, 2],
[2, 2]]])
In [9]: m*a
Out[9]:
array([[[ 9, 20],
[15, 40]],
[[ 3, 10],
[ 6, 10]]])
That's the same as m*a[None,None,:]. When broadcasting, numpy automatically adds dimensions at the beginning as needed. Or iteratively:
In [6]: m[:,:,0]*3
Out[6]:
array([[ 9, 15],
[ 3, 6]])
In [7]: m[:,:,1]*5
Out[7]:
array([[20, 40],
[10, 10]])
Since m is (2,2,2) shape, we can't off hand tell which axis a is supposed to multiply.
According to the accepted answer, you want to multiply along the middle axis
In [16]: m*a[None,:,None]
Out[16]:
array([[[ 9, 12],
[25, 40]],
[[ 3, 6],
[10, 10]]])
But what if m was (2,3,2) in shape? a would then have to have 3 values
In [17]: m=np.array([[[3,4],[5,8],[0,0]],[[1,2],[2,2],[1,1]]])
In [18]: m*a[None,:,None]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-18-f631c33646b7> in <module>()
----> 1 m*a[None,:,None]
ValueError: operands could not be broadcast together with shapes (2,3,2) (1,2,1)
The alternative broadcastings work
In [19]: m*a[:,None,None]
Out[19]:
array([[[ 9, 12],
[15, 24],
[ 0, 0]],
[[ 5, 10],
[10, 10],
[ 5, 5]]])
In [20]: m*a[None,None,:]
Out[20]:
array([[[ 9, 20],
[15, 40],
[ 0, 0]],
[[ 3, 10],
[ 6, 10],
[ 3, 5]]])
Now if m had distinct dimensions, e.g. (3,1000,2), we could tell at a glance with axis a 2 element weight array would work with.

Elementwise multiplication ignoring certain rows of a matrix

Let's say I have a matrix like this:
import numpy as np
a = np.array([[1, 2, 3], [89, 43, 2], [12, -3, 4], [-2, 4, 7]])
array([[ 1, 2, 3],
[89, 43, 2],
[12, -3, 4],
[-2, 4, 7]])
and a vector that looks like this:
b = np.array([1, 2, 3])
If I now want to do a elementwise multiplication I can simply do
c = a * b
and obtain
array([[ 1, 4, 9],
[89, 86, 6],
[12, -6, 12],
[-2, 8, 21]])
My question is: How can I do this kind of multiplication only for certain rows in my matrix? I currently do it like this:
E = a.copy()
# ignore these rows
ignInd = [1, 3]
for ind in xrange(a.shape[0]):
if ind not in ignInd:
E[ind, :] = a[ind, :] * b
The matrix E looks as desired (the rows 1 and 3 are the same as in a):
array([[ 1, 4, 9],
[89, 43, 2],
[12, -6, 12],
[-2, 4, 7]])
Can someone come up with a smarter solution than this?
It seems like you could just do the multiplication and then put back the original data where you want to ignore ...
>>> import numpy as np
>>> a = np.array([[1,2,3],[89,43,2],[12, -3, 4], [-2, 4, 7]])
>>> b = np.array([1,2,3])
>>> c = a * b
>>> ignInd = [1,3]
>>> c[ignInd, :]
array([[89, 86, 6],
[-2, 8, 21]])
>>> c[ignInd, :] = a[ignInd, :]
>>> c
array([[ 1, 4, 9],
[89, 43, 2],
[12, -6, 12],
[-2, 4, 7]])
You can index an NumPy array directly with another NumPy array. In your case, you have the indexes of rows you want to ignore, so you can build an array of indexes to include from this:
In [21]: ignInd = [1,3] #ignore these rows
In [22]: ind = np.array([i for i in range(a.shape[0]) if i not in ignInd])
In [23]: E2 = a.copy()
In [24]: E2[ind,:] = a[ind,:]*b
In [25]: E2
Out[25]:
array([[ 1, 4, 9],
[89, 43, 2],
[12, -6, 12],
[-2, 4, 7]])
EDIT: as #DSM comments, for large arrays it would be more efficient to build the index array using NumPy's vectorized methods, viz. ind = np.setdiff1d(np.arange(len(a)), ignInd) instead of the list comprehension used above.
You can use boolean indexing with np.in1d to select the rows excluded in the give indices list. The implementation would look something like this -
E = a.copy()
mask = ~np.in1d(np.arange(a.shape[0]),ignInd,)
E[mask] = a[mask]*b
For the 1st row in a
a[0] = a[0] * b
..and so on for the other rows.

Indexing tensor with binary matrix in numpy

I have a tensor A such that A.shape = (32, 19, 2) and a binary matrix B such that B.shape = (32, 19). Is there a one-line operation I can perform to get a matrix C, where C.shape = (32, 19) and C(i,j) = A[i, j, B[i,j]]?
Essentially, I want to use B as an indexing matrix, where if B[i,j] = 1 I take A[i,j,1] to form C(i,j).
np.where to the rescue. It's the same principle as mtrw's answer:
In [344]: A=np.arange(4*3*2).reshape(4,3,2)
In [345]: B=np.zeros((4,3),dtype=int)
In [346]: B[[0,1,1,2,3],[0,0,1,2,2]]=1
In [347]: B
Out[347]:
array([[1, 0, 0],
[1, 1, 0],
[0, 0, 1],
[0, 0, 1]])
In [348]: np.where(B,A[:,:,1],A[:,:,0])
Out[348]:
array([[ 1, 2, 4],
[ 7, 9, 10],
[12, 14, 17],
[18, 20, 23]])
np.choose can be used if the last dimension is larger than 2 (but smaller than 32). (choose operates on a list or the 1st dimension, hence the rollaxis.
In [360]: np.choose(B,np.rollaxis(A,2))
Out[360]:
array([[ 1, 2, 4],
[ 7, 9, 10],
[12, 14, 17],
[18, 20, 23]])
B can also be used directly as an index. The trick is to specify the other dimensions in a way that broadcasts to the same shape.
In [373]: A[np.arange(A.shape[0])[:,None], np.arange(A.shape[1])[None,:], B]
Out[373]:
array([[ 1, 2, 4],
[ 7, 9, 10],
[12, 14, 17],
[18, 20, 23]])
This last approach can be modified to work when B does not match the 1st 2 dimensions of A.
np.ix_ may simplify this indexing
I, J = np.ix_(np.arange(4),np.arange(3))
A[I, J, B]
You can do it using list comprehension:
C = np.array([[A[i, j, B[i, j]] for j in range(A.shape[1])] for i in range(A.shape[0])])
C = A[:,:,0]*(B==0) + A[:,:,1]*(B==1) should work. You can generalize this as np.sum([A[:,:,k]*(B==k) for k in np.arange(A.shape[-1])], axis=0) if you need to index more planes.

Categories