Selecting components of vectors in array - python

I have a tensor with shape (7, 2, 3)
I want to select one of the two row vectors from each of the 7 2x3 matrices, i.e.
[
[[0, 0, 0],
[1, 1, 1]],
[[0, 0, 0],
[1, 1, 1]],
...x7
]
to
a = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
...x7
]
b = [
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
...x7
]
each with shape (7, 3).
How can I do this without reshape? (I find reshape to be kind of confusing when some dimensions are the same).
I also know of
np.array(map(lambda item: item[0], x)))
but I would like a more concise way if there is one.

just use looped indexing: data[:, i, :] where i loops from 0 through 1
import numpy as np
a = np.array([
[[0, 0, 0],
[1, 1, 1]],
[[0, 0, 0],
[1, 1, 1]]
])
print(a[:, 1, :])
will produce
[[1 1 1]
[1 1 1]]

Related

Concatenating two 1d numpy to create a Cartesian product of 2d numpy

I want to create a Cartesian product of two numpy so that the first numpy will be the rows and the second will be the columns.
For example get these two numpys:
a = np.array([0,0])
b = np.array([0,1,2,3])
The expected result should be 2d numpy like this:
[[0 0 0]
[0 0 1]
[0 0 2]
[0 0 3]]
The following code does not produce the requested result:
a = np.array([0,0])
b = np.array([0,1,2,3])
_new_ = []
for idx in range(len(a)):
for i in a:
newArr = np.append(a[idx], b)
_new_.append(newArr)
print(np.stack(_new_))
What needs to be changed to produce the desired result?
You can use np.tile with np.column_stack
np.column_stack([np.tile(a, (len(b), 1)), b])
array([[0, 0, 0],
[0, 0, 1],
[0, 0, 2],
[0, 0, 3]])
If you have a a as 2D array
a = np.array([[0, 0], [1, 1]])
b = np.array([0,1,2,3])
np.c_[np.tile(a, (len(b), 1)), np.repeat(b, len(a), axis=0)]
array([[0, 0, 0],
[1, 1, 0],
[0, 0, 1],
[1, 1, 1],
[0, 0, 2],
[1, 1, 2],
[0, 0, 3],
[1, 1, 3]])

How to create an array of binary digits of given unsigned integer numbers with Numpy?

I have an array of numbers between 0 and 3 and I want to create a 2D array of their binary digits.
in the future may be I need to have array of numbers between 0 and 7 or 0 to 15.
Currently my array is defined like this:
a = np.array([[0], [1], [2], [3]], dtype=np.uint8)
I used numpy unpackbits function:
b = np.unpackbits(a, axis=1)
and the result is this :
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1, 1]], dtype=uint8)
As you can see it created a 2d array with 8 items in column while I'm looking for 2 columns 2d array.
here is my desired array:
array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
Is this related to data type uint8 ?
what is your idea?
One way of approaching the problem is to just adapt your b to match your desired output via a simple slicing, similarly to what suggested in #GrzegorzSkibinski answer:
import numpy as np
def gen_bits_by_val(values):
n = int(max(values)).bit_length()
return np.unpackbits(values, axis=1)[:, -n:].copy()
print(gen_bits_by_val(a))
# [[0 0]
# [0 1]
# [1 0]
# [1 1]]
Alternatively, you could create a look-up table, similarly to what suggested in #WarrenWeckesser answer, using the following:
import numpy as np
def gen_bits_by_num(n):
values = np.arange(2 ** n, dtype=np.uint8).reshape(-1, 1)
return np.unpackbits(values, axis=1)[:, -n:].copy()
bits2 = gen_bits_by_num(2)
print(bits2)
# [[0 0]
# [0 1]
# [1 0]
# [1 1]]
which allows for all kind of uses thereby indicated, e.g.:
bits4 = gen_bits_by_num(4)
print(bits4[[1, 3, 12]])
# [[0 0 0 1]
# [0 0 1 1]
# [1 1 0 0]]
EDIT
Considering #PaulPanzer answer the line:
return np.unpackbits(values, axis=1)[:, -n:]
has been replaced with:
return np.unpackbits(values, axis=1)[:, -n:].copy()
which is more memory efficient.
It could have been replaced with:
return np.unpackbits(values << (8 - n), axis=1, count=n)
with similar effects.
You can use the count keyword. It cuts from the right so you also have to shift bits before applying unpackbits.
b = np.unpackbits(a<<6, axis=1, count=2)
b
# array([[0, 0],
# [0, 1],
# [1, 0],
# [1, 1]], dtype=uint8)
This produces a "clean" array:
b.flags
# C_CONTIGUOUS : True
# F_CONTIGUOUS : False
# OWNDATA : True
# WRITEABLE : True
# ALIGNED : True
# WRITEBACKIFCOPY : False
# UPDATEIFCOPY : False
In contrast, slicing the full 8-column output of unpackbits is in a sense a memory leak because the discarded columns will stay in memory as long as the slice lives.
You can truncate b to keep just the columns since the first column with 1:
b=b[:, int(np.argwhere(b.max(axis=0)==1)[0]):]
For such a small number of bits, you can use a lookup table.
For example, here bits2 is an array with shape (4, 2) that holds the bits of the integers 0, 1, 2, and 3. Index bits2 with the values from a to get the bits:
In [43]: bits2 = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
In [44]: a = np.array([[0], [1], [2], [3]], dtype=np.uint8)
In [45]: bits2[a[:, 0]]
Out[45]:
array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
This works fine for 3 or 4 bits, too:
In [46]: bits4 = np.array([[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 0, 1, 1], [0, 1, 0, 0], [
...: 0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 1], [1, 0, 1, 0], [1, 0,
...: 1, 1], [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 1, 1, 1]])
In [47]: bits4
Out[47]:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 1, 1, 1]])
In [48]: x = np.array([0, 1, 5, 14, 9, 8, 15])
In [49]: bits4[x]
Out[49]:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 1, 0, 1],
[1, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 0],
[1, 1, 1, 1]])

Smart Indexing with numpy

I have an 4 dimensional array (named colors) which assigns a color (ie 3 values R, G, B) to each 3d point (x, y, z) -> (r, g, b)
I have another 2 dimensional array (named visible) which tells me which z pane I can see when I look down on it (x, y)->z
I want to create 3 dimensional array (view) which tells me what I see. (x, y) -> (r, g, b)
How can I do that with numpy smart indexing?
I tried
colors=np.array([
[
[[0, 0, 0], [1, 0, 0]],
[[0, 1, 0], [0, 0, 1]]],
[
[[1, 0, 1], [1, 1, 0]],
[[0, 1, 1], [1, 1, 1]]]])
visible=np.array(
[[0, 1],
[1, 0]])
view=colors[:, :,visible[:, :]]
expected=np.array(
[[[0, 0, 0], [1, 1, 0]],
[[0, 1, 1], [0, 0, 1]]])
But that gives me 5 dimensional array.
You can use this:
x = np.array([[0,1],[0,1]])
y = np.array([[0,0],[1,1]])
colors[(visible, y, x)]
It gives:
array([[[0, 0, 0],
[1, 1, 0]],
[[0, 1, 1],
[0, 0, 1]]])
x and y select which pixels you want, while visible is your z plane selector. They can actually be 1D and they will broadcast to fill the other dimension. You can construct arbitrary-size x and y like this:
x = np.arange(colors.shape[2])
y = np.arange(colors.shape[1]).reshape(-1,1) # transpose
Your problem was quite interesting and challenging.
Numpy's advanced indexing works a bit other like you tried to use it intuitively.
There are more options to achieve what you want:
1. You can use advanced indexing as follows using with a bit help of numpy.indices():
import numpy as np
colors=np.array([
[
[[0, 0, 0], [1, 0, 0]],
[[0, 1, 0], [0, 0, 1]]],
[
[[1, 0, 1], [1, 1, 0]],
[[0, 1, 1], [1, 1, 1]]]])
visible = np.array(
[[0, 1],
[1, 0]])
x_ind, y_ind = np.indices(visible.shape)
view = colors[visible, x_ind, y_ind]
print(view)
Out:
[[[0 0 0]
[1 1 0]]
[[0 1 1]
[0 0 1]]]
2. Alternatively you can use numpy.choose() which is very intuitive way in this case:
import numpy as np
colors=np.array([
[
[[0, 0, 0], [1, 0, 0]],
[[0, 1, 0], [0, 0, 1]]],
[
[[1, 0, 1], [1, 1, 0]],
[[0, 1, 1], [1, 1, 1]]]])
visible = np.array(
[[0, 1],
[1, 0]])
visible = visible.reshape(2,2,1)
view = np.choose(visible, colors)
print(view)
Out:
[[[0 0 0]
[1 1 0]]
[[0 1 1]
[0 0 1]]]

Transpose of a 3d list

I have tried this the below mentioned code:
counts=[[[(col.count(i)) for i in range(1,n)] for col in matrix] for matrix in lists]
print(counts)
and the code gives me
[[[1, 1, 1, 1, 0], [1, 1, 1, 0, 1], [1, 1, 0, 1, 1]], [[4, 0, 0, 0, 0], [1, 2, 1, 0, 0], [0, 0, 1, 3, 0]]]
this output
here 3, 5 element list created. I want 5, 3 element list. The output should look like:
[[[1, 1, 1], [1, 0, 1], [1, 1, 0], [1, 1, 1], [0, 1, 1]], [[4, 0, 0], [0, 0, 1], [2, 1, 0], [0, 0, 0], [1, 3, 0]]]
what kind of work should be performed on 'counts' list so that I get this desired output.
you don't really transpose anything as far as i can tell; this is just a reshaping. numpy lets you do that this way:
import numpy as np
lst = [[[1, 1, 1, 1, 0], [1, 1, 1, 0, 1], [1, 1, 0, 1, 1]],
[[4, 0, 0, 0, 0], [1, 2, 1, 0, 0], [0, 0, 1, 3, 0]]]
arr = np.array(lst)
res = arr.reshape((2, 5, 3))
which gives:
[[[1 1 1]
[1 0 1]
[1 1 0]
[1 1 1]
[0 1 1]]
[[4 0 0]
[0 0 1]
[2 1 0]
[0 0 0]
[1 3 0]]]

Substitute item in numpy array with list

I want to replace an item in a numpy array composed of 0 and 1.
I want to replace 1 with the list [0,1] and the 0 with the list [1,0].
I found the function numpy.where(), but it doesn't work with lists.
Is there a function or something similar to do the equivalent for numpy.where(vector==1,[0,1], [1,0]) ?
Simple indexing should do the job:
In [156]: x = np.array([0,1,0,0,1,1,0])
In [157]: y = np.array([[1,0],[0,1]])
In [158]: y[x]
Out[158]:
array([[1, 0],
[0, 1],
[1, 0],
[1, 0],
[0, 1],
[0, 1],
[1, 0]])
And just to be sure this is a general solution, not some 'boolean' fluke
In [162]: x = np.array([0,1,0,0,1,2,2])
In [163]: y = np.array([[1,0],[0,1],[1,1]])
In [164]: y[x]
Out[164]:
array([[1, 0],
[0, 1],
[1, 0],
[1, 0],
[0, 1],
[1, 1],
[1, 1]])
You can actually use where for that if you wish:
>>> import numpy as np
>>> vector = np.random.randint(0, 2, (8, 8))
>>> vector
array([[1, 0, 0, 0, 0, 0, 1, 1],
[1, 1, 0, 1, 0, 0, 0, 1],
[1, 0, 0, 1, 1, 1, 0, 0],
[1, 0, 1, 1, 0, 0, 0, 0],
[0, 1, 0, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 0, 0, 0, 0],
[0, 1, 1, 0, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0]])
>>> np.where(vector[..., None] == 1, [0,1], [1,0])
# btw. if vector has only 0 and 1 entries you can leave out the " == 1 "
array([[[0, 1],
[1, 0],
[1, 0],
[1, 0],
[1, 0],
[1, 0],
[0, 1],
[0, 1]],
[[0, 1],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[1, 0],
[1, 0],
etc.
Looks like you want to make one-hot vector encoding:
a = np.array([1, 0, 1, 1, 0]) # initial array
b = np.zeros((len(a), 2)) # where 2 is number of classes
b[np.arange(len(a)), a] = 1
print(b)
result:
array([[ 0., 1.],
[ 1., 0.],
[ 0., 1.],
[ 0., 1.],
[ 1., 0.]])
Since it's not possible to grow the array dynamically in NumPy, you've to convert the array to list, do the substitution as desired, and then convert the result back to NumPy array like:
In [21]: vector = np.array([0, 0, 1, 0, 1])
In [22]: vlist = vector.tolist()
In [23]: vlist
Out[23]: [0, 0, 1, 0, 1]
In [24]: new_list = [[1, 0] if el == 0 else [0, 1] for idx, el in enumerate(vlist)]
In [25]: result = np.array(new_list)
In [26]: result
Out[26]:
array([[1, 0],
[1, 0],
[0, 1],
[1, 0],
[0, 1]])
If your 1D array is not that large enough, then list comprehension is not that bad of an approach.
hpaulj's answer would be the ideal way of doing this. An alternative is to reshape your original numpy array, and apply your standard np.where() operation.
import numpy as np
x = np.array([0,1,0,0,1,1,0])
x = np.reshape(x,(len(x),1))
# Equivalently, if you want to be explicit:
# x = np.array([[e] for e in x])
print np.where(x==1,[1,0],[0,1])
# Result:
array([[0, 1],
[1, 0],
[0, 1],
[0, 1],
[1, 0],
[1, 0],
[0, 1]])

Categories

Resources