Related
i want to generate a diagonal matrix with size such as nxn
This is a toeplitz matrix, you can use SciPy's linalg.toeplitz to construct such a pattern. You can look at its implementation code here which uses from np.lib.stride_tricks.as_strided under the hood.
>>> toeplitz(-np.arange(3), np.arange(3))
array([[ 0, 1, 2],
[-1, 0, 1],
[-2, -1, 0]])
>>> toeplitz(-np.arange(6), np.arange(6))
array([[ 0, 1, 2, 3, 4, 5],
[-1, 0, 1, 2, 3, 4],
[-2, -1, 0, 1, 2, 3],
[-3, -2, -1, 0, 1, 2],
[-4, -3, -2, -1, 0, 1],
[-5, -4, -3, -2, -1, 0]])
It's quite easy to write as a custom function:
def diagonal(N):
a = np.arange(N)
return a-a[:,None]
diagonal(3)
array([[ 0, 1, 2],
[-1, 0, 1],
[-2, -1, 0]])
diagonal(6)
array([[ 0, 1, 2, 3, 4, 5],
[-1, 0, 1, 2, 3, 4],
[-2, -1, 0, 1, 2, 3],
[-3, -2, -1, 0, 1, 2],
[-4, -3, -2, -1, 0, 1],
[-5, -4, -3, -2, -1, 0]])
I am having trouble with some code I am attempting to write.
I am attempting to take a list of lists of coordinates (representing possible positions of a shape in 3D) and form a list which consists of all the elements in the original list and additionally the elements in the original list rotated so that the [x, y, z] coordinates are shifted to include [z, x, y] and [y, z, x] also.
I think this is better illustrated with an example:
Taking the list (representing the possible positions of a 2x2x1 block, hence "two_by_two"):
two_by_two = [
[[-1, -1, 1], [-1, -1, 0], [-1, 0, 0], [-1, 0, 1]],
[[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]]
...
]
(the ellipses representing more similar lists of coordinates) I am attempting to form the complete list:
two_by_two_comp = [
[[-1, -1, 1], [-1, -1, 0], [-1, 0, 0], [-1, 0, 1]],
[[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]]
...
[[1, -1, -1], [0, -1, -1], [0, -1, 0], [1, -1, 0]],
[[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]]
...
[[-1, 1, -1], [-1, 0, -1], [0, 0, -1], [0, 1, -1]],
[[-1, 0, -1], [-1, -1, -1], [0, -1, -1], [0, 0, -1]]
...
]
I hope that this is clear.
I am attempting to achieve this by using a function which shifts all of the coordinates in two_by_two:
# function to change [x, y, z] to [z, x, y]
def rotate_coordinates(parameter):
coord_list = parameter[len(parameter) - 1]
coordinates = coord_list[len(coord_list) - 1]
z_coordinate = coordinates[2]
coordinates.pop()
coordinates.insert(0, z_coordinate)
# function to change list[x, y, z] to list[z, x, y]
def rotate_coord_list(parameter):
coord_list = parameter[len(parameter) - 1]
a = len(coord_list)
while a > 0:
coordinates = coord_list[len(coord_list) - 1]
rotate_coordinates(parameter)
coord_list.pop()
coord_list.insert(0, coordinates)
a = a - 1
# function to change list[list[x, y, z]] to list[list[z, x, y]]
def rotate_positions_list(parameter):
b = len(parameter)
while b > 0:
coord_list = parameter[len(parameter) - 1]
rotate_coord_list(parameter)
parameter.pop()
parameter.insert(0, coord_list)
b = b - 1
This seems to me to be successful in that when I run:
print(two_by_two)
rotate_positions_list(two_by_two)
print(two_by_two)
It outputs:
[[[-1, -1, 1], [-1, -1, 0], [-1, 0, 0], [-1, 0, 1]],
[[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]]
...]
[[[1, -1, -1], [0, -1, -1], [0, -1, 0], [1, -1, 0]],
[[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]]
...]
And so it shifts all of the coordinates as I intended, the issue arises when I try to begin creating two_by_two_comp as so:
two_by_two_comp = []
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)
rotate_positions_list(two_by_two)
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)
Which returns:
[[[-1, -1, 1], [-1, -1, 0], [-1, 0, 0], [-1, 0, 1]],
[[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]]
...]
[[[1, -1, -1], [0, -1, -1], [0, -1, 0], [1, -1, 0]],
[[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]],
...
[[1, -1, -1], [0, -1, -1], [0, -1, 0], [1, -1, 0]],
[[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]]
...]
So I end up with the same "version" of two_by_two copied as opposed to the shifted and original version, and I have no idea why the section of two_by_two_comp which I print out first gets affected by the rotate_positons_list(two_by_two) function.
If anyone could clear up my confusion, I would be very grateful. I will include the full script in one piece below.
Thank you,
Dan
two_by_two = [
[[-1, -1, 1], [-1, -1, 0], [-1, 0, 0], [-1, 0, 1]],
[[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]],
[[-1, 0, 0], [-1, 0, -1], [-1, 1, -1], [-1, 1, 0]],
[[-1, 0, 1], [-1, 0, 0], [-1, 1, 0], [-1, 1, 1]],
[[0, -1, 1], [0, -1, 0], [0, 0, 0], [0, 0, 1]],
[[0, -1, 0], [0, -1, -1], [0, 0, -1], [0, 0, 0]],
[[0, 0, 0], [0, 0, -1], [0, 1, -1], [0, 1, 0]],
[[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]],
[[1, -1, 1], [1, -1, 0], [1, 0, 0], [1, 0, 1]],
[[1, -1, 0], [1, -1, -1], [1, 0, -1], [1, 0, 0]],
[[1, 0, 0], [1, 0, -1], [1, 1, -1], [1, 1, 0]],
[[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]],
]
# function to change [x, y, z] to [z, x, y]
def rotate_coordinates(parameter):
coord_list = parameter[len(parameter) - 1]
coordinates = coord_list[len(coord_list) - 1]
z_coordinate = coordinates[2]
coordinates.pop()
coordinates.insert(0, z_coordinate)
# function to change list[x, y, z] to list[z, x, y]
def rotate_coord_list(parameter):
coord_list = parameter[len(parameter) - 1]
a = len(coord_list)
while a > 0:
coordinates = coord_list[len(coord_list) - 1]
rotate_coordinates(parameter)
coord_list.pop()
coord_list.insert(0, coordinates)
a = a - 1
# function to change list[list[x, y, z]] to list[list[z, x, y]]
def rotate_positions_list(parameter):
b = len(parameter)
while b > 0:
coord_list = parameter[len(parameter) - 1]
rotate_coord_list(parameter)
parameter.pop()
parameter.insert(0, coord_list)
b = b - 1
two_by_two_comp = []
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)
rotate_positions_list(two_by_two)
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)
Your problem lies in the difference between deep copy and shallow copy. As per the docs
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.
The problematic line is thus:
two_by_two_comp.extend(two_by_two)
Let me illustrate with an example using two lists a and b:
a = [[2, 3, 4], [1, 2, 3]]
b = []
b.extend(a)
Now let's say I modify something inside a:
a[0].append(3)
print(a) # [[2, 3, 4, 3], [1, 2, 3]]
Everything is fine, but have a look at what happened to b in the meantime:
print(b) # [[2, 3, 4, 3], [1, 2, 3]]
It was also modified.
To achieve what you want, you need to create a deep copy of two_by_two otherwise you will just be referencing the same memory address. Long story short, instead of:
two_by_two_comp.extend(two_by_two)
You must do:
two_by_two_comp.extend(copy.deepcopy(two_by_two))
Don't forget to import the copy module at the top of your script:
import copy
I want to define an array with a given number of columns (let's say n=5) and in each cell of the array, the value can be either 0 or 1. And I would like to create all possibilities of ones and zeros, which means, that each row would represent one possible vector with n elements.
In other words, I want the table to look like this:
I know that create the vector of ones and zeros is quite easy but how can I ensure that the vectors would not repeat in the table and that there will be all possible combinations included (If my math is correct the table should have 2**5 = 32 rows)
How can I do it in Python? Thank you very much
Easy with itertools:
itertools.product(*[[0, 1]] * 3)
results in
[(0, 0, 0),
(0, 0, 1),
(0, 1, 0),
(0, 1, 1),
(1, 0, 0),
(1, 0, 1),
(1, 1, 0),
(1, 1, 1)]
You could generate all the numbers up to 32, and convert each to binary representation using bit shifts.
combs = [[(n >> p) & 1 for p in range(4, -1, -1)] for n in range(32)]
which gives combs as:
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 1],
[0, 0, 1, 1, 0],
[0, 0, 1, 1, 1],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 1],
[0, 1, 1, 0, 0],
[0, 1, 1, 0, 1],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 1],
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 1],
[1, 0, 0, 1, 0],
[1, 0, 0, 1, 1],
[1, 0, 1, 0, 0],
[1, 0, 1, 0, 1],
[1, 0, 1, 1, 0],
[1, 0, 1, 1, 1],
[1, 1, 0, 0, 0],
[1, 1, 0, 0, 1],
[1, 1, 0, 1, 0],
[1, 1, 0, 1, 1],
[1, 1, 1, 0, 0],
[1, 1, 1, 0, 1],
[1, 1, 1, 1, 0],
[1, 1, 1, 1, 1]
]
Alternatively, you could use a recursive generation function:
def gimme_combs(n):
if n == 1: return [[0], [1]]
lower_combs = gimme_combs(n - 1)
return [[0] + c for c in lower_combs] + \
[[1] + c for c in lower_combs]
which would give the same result when called with:
combs = gimme_combs(5)
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]])
I have a ndarray, and I want to set all the non-maximum elements in the last dimension to be zero.
a = np.array([[[1,8,3,4],[6,7,10,6],[11,12,15,4]],
[[4,2,3,4],[4,7,9,8],[41,14,15,3]],
[[4,22,3,4],[16,7,9,8],[41,12,15,43]]
])
print(a.shape)
(3,3,4)
I can get the indexes of maximum elements by np.argmax():
b = np.argmax(a, axis=2)
b
array([[1, 2, 2],
[0, 2, 0],
[1, 0, 3]])
Obviously, b has 1 dimension less than a. Now, I want to get a new 3-d array that has all zeros except for where the maximum values are.
I want to get this array:
np.array([[[0,1,0,0],[0,0,1,0],[0,0,1,0]],
[[1,0,0,1],[0,0,1,0],[1,0,0,0]],
[[0,1,0,0],[1,0,0,0],[0,0,0,1]]
])
One way to achieve this, I tried creating these temporary arrays
b = np.repeat(b[:,:,np.newaxis], 4, axis=2)
t = np.repeat(np.arange(4).reshape(4,1), 9, axis=1).T.reshape(b.shape)
z = np.zeros(shape=a.shape, dtype=int)
z[t == b] = 1
z
array([[[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 1, 0]],
[[1, 0, 0, 0],
[0, 0, 1, 0],
[1, 0, 0, 0]],
[[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, 1]]])
Any idea how to get this in a more efficient way?
Here's one way that uses broadcasting:
In [108]: (a == a.max(axis=2, keepdims=True)).astype(int)
Out[108]:
array([[[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 1, 0]],
[[1, 0, 0, 1],
[0, 0, 1, 0],
[1, 0, 0, 0]],
[[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, 1]]])