Numpy 2-D array boolean masking - arrays

I don't understand one example in this numpy tutorial.
a = np.arange(12).reshape(3,4)
b1 = np.array([False, True, True])
b2 = np.array([True, False, True, False])
Then why will a[b1,b2] return array([4, 10])? Shouldn't it return array([[4, 6], [8, 10]])?
Any detailed explanation is appreciated!

When you index an array with multiple arrays, it indexes with pairs of elements from the indexing arrays
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b1
array([False, True, True], dtype=bool)
>>> b2
array([ True, False, True, False], dtype=bool)
>>> a[b1, b2]
array([ 4, 10])
Notice that this is equivalent to:
>>> a[(1, 2), (0, 2)]
array([ 4, 10])
which are the elements at a[1, 0] and a[2, 2]
>>> a[1, 0]
4
>>> a[2, 2]
10
Because of this pairwise behavior, you cannot in general index with separate length arrays (they have to be able to broadcast). So this example is sort of an accident since both indexing arrays have two indices where they are True; if one had three True values for example, you'd get an error:
>>> b3 = np.array([True, True, True, False])
>>> a[b1, b3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
So this is specifically letting you know that the indexing arrays must be able to be broadcast together (so that it can chip off indices together in a smart way; e.g. if one indexing array just had a single value, that would be repeated with each value from the other indexing array).
To get the results you expect, you could index the result separately:
>>> a[b1][:, b2]
array([[ 4, 6],
[ 8, 10]])
Otherwise, you could also turn your index array into a 2D array with the same shape as a, but note that if you do that the result will be a linear array (since any number of elements could be pulled out, which of course might not be square):
>>> a[np.outer(b1, b2)]
array([ 4, 6, 8, 10])

The indices of true for the first array are
>>> i = np.where(b1)
>>> i
array([1,2])
For the second array they are
>>> j = np.where(b2)
>>> j
array([0,1])
Using these index masks together,
>>> a[i,j]
array([4, 10])

Another way to apply a general boolean 2D mask on a 2D numpy array is the following:
Use matrix element-wise multiplication:
import numpy as np
n = 100
mask = np.identity(n)
data = np.random.rand(n,n)
data_masked = data * mask
In this random example, you are keeping only the elements on the diagonal. The mask could be any n by n matrix though.

Related

arrays in array items linking when using .extend python [duplicate]

I created a list of lists:
>>> xs = [[1] * 4] * 3
>>> print(xs)
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
Then, I changed one of the innermost values:
>>> xs[0][0] = 5
>>> print(xs)
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
Why did every first element of each sublist change to 5?
See also:
How do I clone a list so that it doesn't change unexpectedly after assignment? for workarounds for the problem
List of dictionary stores only last appended value in every iteration for an analogous problem with a list of dicts
How do I initialize a dictionary of empty lists in Python? for an analogous problem with a dict of lists
When you write [x]*3 you get, essentially, the list [x, x, x]. That is, a list with 3 references to the same x. When you then modify this single x it is visible via all three references to it:
x = [1] * 4
xs = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(xs[0]): {id(xs[0])}\n"
f"id(xs[1]): {id(xs[1])}\n"
f"id(xs[2]): {id(xs[2])}"
)
# id(xs[0]): 140560897920048
# id(xs[1]): 140560897920048
# id(xs[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"xs: {xs}")
# xs: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
To fix it, you need to make sure that you create a new list at each position. One way to do it is
[[1]*4 for _ in range(3)]
which will reevaluate [1]*4 each time instead of evaluating it once and making 3 references to 1 list.
You might wonder why * can't make independent objects the way the list comprehension does. That's because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.
The only option * has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.
In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)] reevaluates [1] * 4 every time for the same reason [x**2 for x in range(3)] reevaluates x**2 every time. Every evaluation of [1] * 4 generates a new list, so the list comprehension does what you wanted.
Incidentally, [1] * 4 also doesn't copy the elements of [1], but that doesn't matter, since integers are immutable. You can't do something like 1.value = 2 and turn a 1 into a 2.
size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for _ in range(size)]
Live visualization using Python Tutor:
Actually, this is exactly what you would expect. Let's decompose what is happening here:
You write
lst = [[1] * 4] * 3
This is equivalent to:
lst1 = [1]*4
lst = [lst1]*3
This means lst is a list with 3 elements all pointing to lst1. This means the two following lines are equivalent:
lst[0][0] = 5
lst1[0] = 5
As lst[0] is nothing but lst1.
To obtain the desired behavior, you can use a list comprehension:
lst = [ [1]*4 for n in range(3) ]
In this case, the expression is re-evaluated for each n, leading to a different list.
[[1] * 4] * 3
or even:
[[1, 1, 1, 1]] * 3
Creates a list that references the internal [1,1,1,1] 3 times - not three copies of the inner list, so any time you modify the list (in any position), you'll see the change three times.
It's the same as this example:
>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
where it's probably a little less surprising.
my_list = [[1]*4] * 3 creates one list object [1,1,1,1] in memory and copies its reference 3 times over. This is equivalent to obj = [1,1,1,1]; my_list = [obj]*3. Any modification to obj will be reflected at three places, wherever obj is referenced in the list.
The right statement would be:
my_list = [[1]*4 for _ in range(3)]
or
my_list = [[1 for __ in range(4)] for _ in range(3)]
Important thing to note here is that the * operator is mostly used to create a list of literals. Although 1 is immutable, obj = [1]*4 will still create a list of 1 repeated 4 times over to form [1,1,1,1]. But if any reference to an immutable object is made, the object is overwritten with a new one.
This means if we do obj[1] = 42, then obj will become [1,42,1,1] not [42,42,42,42] as some may assume. This can also be verified:
>>> my_list = [1]*4
>>> my_list
[1, 1, 1, 1]
>>> id(my_list[0])
4522139440
>>> id(my_list[1]) # Same as my_list[0]
4522139440
>>> my_list[1] = 42 # Since my_list[1] is immutable, this operation overwrites my_list[1] with a new object changing its id.
>>> my_list
[1, 42, 1, 1]
>>> id(my_list[0])
4522139440
>>> id(my_list[1]) # id changed
4522140752
>>> id(my_list[2]) # id still same as my_list[0], still referring to value `1`.
4522139440
Alongside the accepted answer that explained the problem correctly, instead of creating a list with duplicated elements using following code:
[[1]*4 for _ in range(3)]
Also, you can use itertools.repeat() to create an iterator object of repeated elements:
>>> a = list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0] = 5
>>> a
[5, 1, 1, 1]
P.S. If you're using NumPy and you only want to create an array of ones or zeroes you can use np.ones and np.zeros and/or for other numbers use np.repeat:
>>> import numpy as np
>>> np.ones(4)
array([1., 1., 1., 1.])
>>> np.ones((4, 2))
array([[1., 1.],
[1., 1.],
[1., 1.],
[1., 1.]])
>>> np.zeros((4, 2))
array([[0., 0.],
[0., 0.],
[0., 0.],
[0., 0.]])
>>> np.repeat([7], 10)
array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])
Python containers contain references to other objects. See this example:
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]
In this b is a list that contains one item that is a reference to list a. The list a is mutable.
The multiplication of a list by an integer is equivalent to adding the list to itself multiple times (see common sequence operations). So continuing with the example:
>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]
We can see that the list c now contains two references to list a which is equivalent to c = b * 2.
Python FAQ also contains explanation of this behavior: How do I create a multidimensional list?
In simple words this is happening because in python everything works by reference, so when you create a list of list that way you basically end up with such problems.
To solve your issue you can do either one of them:
1. Use numpy array documentation for numpy.empty
2. Append the list as you get to a list.
3. You can also use dictionary if you want
Let's rewrite your code in the following way:
x = 1
y = [x]
z = y * 4
my_list = [z] * 3
Then having this, run the following code to make everything more clear. What the code does is basically print the ids of the obtained objects, which
Return[s] the “identity” of an object
and will help us identify them and analyse what happens:
print("my_list:")
for i, sub_list in enumerate(my_list):
print("\t[{}]: {}".format(i, id(sub_list)))
for j, elem in enumerate(sub_list):
print("\t\t[{}]: {}".format(j, id(elem)))
And you will get the following output:
x: 1
y: [1]
z: [1, 1, 1, 1]
my_list:
[0]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[1]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[2]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
So now let's go step-by-step. You have x which is 1, and a single element list y containing x. Your first step is y * 4 which will get you a new list z, which is basically [x, x, x, x], i.e. it creates a new list which will have 4 elements, which are references to the initial x object. The next step is pretty similar. You basically do z * 3, which is [[x, x, x, x]] * 3 and returns [[x, x, x, x], [x, x, x, x], [x, x, x, x]], for the same reason as for the first step.
I am adding my answer to explain the same diagrammatically.
The way you created the 2D, creates a shallow list
arr = [[0]*cols]*row
Instead, if you want to update the elements of the list, you should use
rows, cols = (5, 5)
arr = [[0 for i in range(cols)] for j in range(rows)]
Explanation:
One can create a list using:
arr = [0]*N
or
arr = [0 for i in range(N)]
In the first case all the indices of the array point to the same integer object
and when you assign a value to a particular index, a new int object is created, for example arr[4] = 5 creates
Now let us see what happens when we create a list of list, in this case, all the elements of our top list will point to the same list
And if you update the value of any index a new int object will be created. But since all the top-level list indexes are pointing at the same list, all the rows will look the same. And you will get the feeling that updating an element is updating all the elements in that column.
Credits: Thanks to Pranav Devarakonda for the easy explanation here
Everyone is explaining what is happening. I'll suggest one way to solve it:
my_list = [[1 for i in range(4)] for j in range(3)]
my_list[0][0] = 5
print(my_list)
And then you get:
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#spelchekr from Python list multiplication: [[...]]*3 makes 3 lists which mirror each other when modified and I had the same question about
"Why does only the outer *3 create more references while the inner one doesn't? Why isn't it all 1s?"
li = [0] * 3
print([id(v) for v in li]) # [140724141863728, 140724141863728, 140724141863728]
li[0] = 1
print([id(v) for v in li]) # [140724141863760, 140724141863728, 140724141863728]
print(id(0)) # 140724141863728
print(id(1)) # 140724141863760
print(li) # [1, 0, 0]
ma = [[0]*3] * 3 # mainly discuss inner & outer *3 here
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
ma[0][0] = 1
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
print(ma) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Here is my explanation after trying the code above:
The inner *3 also creates references, but its references are immutable, something like [&0, &0, &0], then when you change li[0], you can't change any underlying reference of const int 0, so you can just change the reference address into the new one &1;
while ma = [&li, &li, &li] and li is mutable, so when you call ma[0][0] = 1, ma[0][0] is equal to &li[0], so all the &li instances will change its 1st address into &1.
Trying to explain it more descriptively,
Operation 1:
x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]
x[0][0] = 1
print(x) # [[1, 0], [0, 0]]
Operation 2:
y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]
y[0][0] = 1
print(y) # [[1, 0], [1, 0]]
Noticed why doesn't modifying the first element of the first list didn't modify the second element of each list? That's because [0] * 2 really is a list of two numbers, and a reference to 0 cannot be modified.
If you want to create clone copies, try Operation 3:
import copy
y = [0] * 2
print(y) # [0, 0]
y = [y, copy.deepcopy(y)]
print(y) # [[0, 0], [0, 0]]
y[0][0] = 1
print(y) # [[1, 0], [0, 0]]
another interesting way to create clone copies, Operation 4:
import copy
y = [0] * 2
print(y) # [0, 0]
y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]
y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]
By using the inbuilt list function you can do like this
a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list
a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number
a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting
a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list
I arrived here because I was looking to see how I could nest an arbitrary number of lists. There are a lot of explanations and specific examples above, but you can generalize N dimensional list of lists of lists of ... with the following recursive function:
import copy
def list_ndim(dim, el=None, init=None):
if init is None:
init = el
if len(dim)> 1:
return list_ndim(dim[0:-1], None, [copy.copy(init) for x in range(dim[-1])])
return [copy.deepcopy(init) for x in range(dim[0])]
You make your first call to the function like this:
dim = (3,5,2)
el = 1.0
l = list_ndim(dim, el)
where (3,5,2) is a tuple of the dimensions of the structure (similar to numpy shape argument), and 1.0 is the element you want the structure to be initialized with (works with None as well). Note that the init argument is only provided by the recursive call to carry forward the nested child lists
output of above:
[[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]]
set specific elements:
l[1][3][1] = 56
l[2][2][0] = 36.0+0.0j
l[0][1][0] = 'abc'
resulting output:
[[[1.0, 1.0], ['abc', 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 56.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [(36+0j), 1.0], [1.0, 1.0], [1.0, 1.0]]]
the non-typed nature of lists is demonstrated above
While the original question constructed the sublists with the multiplication operator, I'll add an example that uses the same list for the sublists. Adding this answer for completeness as this question is often used as a canonical for the issue
node_count = 4
colors = [0,1,2,3]
sol_dict = {node:colors for node in range(0,node_count)}
The list in each dictionary value is the same object, trying to change one of the dictionaries values will be seen in all.
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> [v is colors for v in sol_dict.values()]
[True, True, True, True]
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 2, 3], 2: [0, 2, 3], 3: [0, 2, 3]}
The correct way to construct the dictionary would be to use a copy of the list for each value.
>>> colors = [0,1,2,3]
>>> sol_dict = {node:colors[:] for node in range(0,node_count)}
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
Note that items in the sequence are not copied; they are referenced multiple times. This often haunts new Python programmers; consider:
>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
What has happened is that [[]] is a one-element list containing an empty list, so all three elements of [[]] * 3 are references to this single empty list. Modifying any of the elements of lists modifies this single list.
Another example to explain this is using multi-dimensional arrays.
You probably tried to make a multidimensional array like this:
>>> A = [[None] * 2] * 3
This looks correct if you print it:
>>> A
[[None, None], [None, None], [None, None]]
But when you assign a value, it shows up in multiple places:
>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]
The reason is that replicating a list with * doesn’t create copies, it only creates references to the existing objects. The 3 creates a list containing 3 references to the same list of length two. Changes to one row will show in all rows, which is almost certainly not what you want.

Python Assigning value to element in 2-D list [duplicate]

I created a list of lists:
>>> xs = [[1] * 4] * 3
>>> print(xs)
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
Then, I changed one of the innermost values:
>>> xs[0][0] = 5
>>> print(xs)
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
Why did every first element of each sublist change to 5?
See also:
How do I clone a list so that it doesn't change unexpectedly after assignment? for workarounds for the problem
List of dictionary stores only last appended value in every iteration for an analogous problem with a list of dicts
How do I initialize a dictionary of empty lists in Python? for an analogous problem with a dict of lists
When you write [x]*3 you get, essentially, the list [x, x, x]. That is, a list with 3 references to the same x. When you then modify this single x it is visible via all three references to it:
x = [1] * 4
xs = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(xs[0]): {id(xs[0])}\n"
f"id(xs[1]): {id(xs[1])}\n"
f"id(xs[2]): {id(xs[2])}"
)
# id(xs[0]): 140560897920048
# id(xs[1]): 140560897920048
# id(xs[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"xs: {xs}")
# xs: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
To fix it, you need to make sure that you create a new list at each position. One way to do it is
[[1]*4 for _ in range(3)]
which will reevaluate [1]*4 each time instead of evaluating it once and making 3 references to 1 list.
You might wonder why * can't make independent objects the way the list comprehension does. That's because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.
The only option * has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.
In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)] reevaluates [1] * 4 every time for the same reason [x**2 for x in range(3)] reevaluates x**2 every time. Every evaluation of [1] * 4 generates a new list, so the list comprehension does what you wanted.
Incidentally, [1] * 4 also doesn't copy the elements of [1], but that doesn't matter, since integers are immutable. You can't do something like 1.value = 2 and turn a 1 into a 2.
size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for _ in range(size)]
Live visualization using Python Tutor:
Actually, this is exactly what you would expect. Let's decompose what is happening here:
You write
lst = [[1] * 4] * 3
This is equivalent to:
lst1 = [1]*4
lst = [lst1]*3
This means lst is a list with 3 elements all pointing to lst1. This means the two following lines are equivalent:
lst[0][0] = 5
lst1[0] = 5
As lst[0] is nothing but lst1.
To obtain the desired behavior, you can use a list comprehension:
lst = [ [1]*4 for n in range(3) ]
In this case, the expression is re-evaluated for each n, leading to a different list.
[[1] * 4] * 3
or even:
[[1, 1, 1, 1]] * 3
Creates a list that references the internal [1,1,1,1] 3 times - not three copies of the inner list, so any time you modify the list (in any position), you'll see the change three times.
It's the same as this example:
>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
where it's probably a little less surprising.
my_list = [[1]*4] * 3 creates one list object [1,1,1,1] in memory and copies its reference 3 times over. This is equivalent to obj = [1,1,1,1]; my_list = [obj]*3. Any modification to obj will be reflected at three places, wherever obj is referenced in the list.
The right statement would be:
my_list = [[1]*4 for _ in range(3)]
or
my_list = [[1 for __ in range(4)] for _ in range(3)]
Important thing to note here is that the * operator is mostly used to create a list of literals. Although 1 is immutable, obj = [1]*4 will still create a list of 1 repeated 4 times over to form [1,1,1,1]. But if any reference to an immutable object is made, the object is overwritten with a new one.
This means if we do obj[1] = 42, then obj will become [1,42,1,1] not [42,42,42,42] as some may assume. This can also be verified:
>>> my_list = [1]*4
>>> my_list
[1, 1, 1, 1]
>>> id(my_list[0])
4522139440
>>> id(my_list[1]) # Same as my_list[0]
4522139440
>>> my_list[1] = 42 # Since my_list[1] is immutable, this operation overwrites my_list[1] with a new object changing its id.
>>> my_list
[1, 42, 1, 1]
>>> id(my_list[0])
4522139440
>>> id(my_list[1]) # id changed
4522140752
>>> id(my_list[2]) # id still same as my_list[0], still referring to value `1`.
4522139440
Alongside the accepted answer that explained the problem correctly, instead of creating a list with duplicated elements using following code:
[[1]*4 for _ in range(3)]
Also, you can use itertools.repeat() to create an iterator object of repeated elements:
>>> a = list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0] = 5
>>> a
[5, 1, 1, 1]
P.S. If you're using NumPy and you only want to create an array of ones or zeroes you can use np.ones and np.zeros and/or for other numbers use np.repeat:
>>> import numpy as np
>>> np.ones(4)
array([1., 1., 1., 1.])
>>> np.ones((4, 2))
array([[1., 1.],
[1., 1.],
[1., 1.],
[1., 1.]])
>>> np.zeros((4, 2))
array([[0., 0.],
[0., 0.],
[0., 0.],
[0., 0.]])
>>> np.repeat([7], 10)
array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])
Python containers contain references to other objects. See this example:
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]
In this b is a list that contains one item that is a reference to list a. The list a is mutable.
The multiplication of a list by an integer is equivalent to adding the list to itself multiple times (see common sequence operations). So continuing with the example:
>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]
We can see that the list c now contains two references to list a which is equivalent to c = b * 2.
Python FAQ also contains explanation of this behavior: How do I create a multidimensional list?
In simple words this is happening because in python everything works by reference, so when you create a list of list that way you basically end up with such problems.
To solve your issue you can do either one of them:
1. Use numpy array documentation for numpy.empty
2. Append the list as you get to a list.
3. You can also use dictionary if you want
Let's rewrite your code in the following way:
x = 1
y = [x]
z = y * 4
my_list = [z] * 3
Then having this, run the following code to make everything more clear. What the code does is basically print the ids of the obtained objects, which
Return[s] the “identity” of an object
and will help us identify them and analyse what happens:
print("my_list:")
for i, sub_list in enumerate(my_list):
print("\t[{}]: {}".format(i, id(sub_list)))
for j, elem in enumerate(sub_list):
print("\t\t[{}]: {}".format(j, id(elem)))
And you will get the following output:
x: 1
y: [1]
z: [1, 1, 1, 1]
my_list:
[0]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[1]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[2]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
So now let's go step-by-step. You have x which is 1, and a single element list y containing x. Your first step is y * 4 which will get you a new list z, which is basically [x, x, x, x], i.e. it creates a new list which will have 4 elements, which are references to the initial x object. The next step is pretty similar. You basically do z * 3, which is [[x, x, x, x]] * 3 and returns [[x, x, x, x], [x, x, x, x], [x, x, x, x]], for the same reason as for the first step.
I am adding my answer to explain the same diagrammatically.
The way you created the 2D, creates a shallow list
arr = [[0]*cols]*row
Instead, if you want to update the elements of the list, you should use
rows, cols = (5, 5)
arr = [[0 for i in range(cols)] for j in range(rows)]
Explanation:
One can create a list using:
arr = [0]*N
or
arr = [0 for i in range(N)]
In the first case all the indices of the array point to the same integer object
and when you assign a value to a particular index, a new int object is created, for example arr[4] = 5 creates
Now let us see what happens when we create a list of list, in this case, all the elements of our top list will point to the same list
And if you update the value of any index a new int object will be created. But since all the top-level list indexes are pointing at the same list, all the rows will look the same. And you will get the feeling that updating an element is updating all the elements in that column.
Credits: Thanks to Pranav Devarakonda for the easy explanation here
Everyone is explaining what is happening. I'll suggest one way to solve it:
my_list = [[1 for i in range(4)] for j in range(3)]
my_list[0][0] = 5
print(my_list)
And then you get:
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#spelchekr from Python list multiplication: [[...]]*3 makes 3 lists which mirror each other when modified and I had the same question about
"Why does only the outer *3 create more references while the inner one doesn't? Why isn't it all 1s?"
li = [0] * 3
print([id(v) for v in li]) # [140724141863728, 140724141863728, 140724141863728]
li[0] = 1
print([id(v) for v in li]) # [140724141863760, 140724141863728, 140724141863728]
print(id(0)) # 140724141863728
print(id(1)) # 140724141863760
print(li) # [1, 0, 0]
ma = [[0]*3] * 3 # mainly discuss inner & outer *3 here
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
ma[0][0] = 1
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
print(ma) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Here is my explanation after trying the code above:
The inner *3 also creates references, but its references are immutable, something like [&0, &0, &0], then when you change li[0], you can't change any underlying reference of const int 0, so you can just change the reference address into the new one &1;
while ma = [&li, &li, &li] and li is mutable, so when you call ma[0][0] = 1, ma[0][0] is equal to &li[0], so all the &li instances will change its 1st address into &1.
Trying to explain it more descriptively,
Operation 1:
x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]
x[0][0] = 1
print(x) # [[1, 0], [0, 0]]
Operation 2:
y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]
y[0][0] = 1
print(y) # [[1, 0], [1, 0]]
Noticed why doesn't modifying the first element of the first list didn't modify the second element of each list? That's because [0] * 2 really is a list of two numbers, and a reference to 0 cannot be modified.
If you want to create clone copies, try Operation 3:
import copy
y = [0] * 2
print(y) # [0, 0]
y = [y, copy.deepcopy(y)]
print(y) # [[0, 0], [0, 0]]
y[0][0] = 1
print(y) # [[1, 0], [0, 0]]
another interesting way to create clone copies, Operation 4:
import copy
y = [0] * 2
print(y) # [0, 0]
y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]
y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]
By using the inbuilt list function you can do like this
a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list
a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number
a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting
a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list
I arrived here because I was looking to see how I could nest an arbitrary number of lists. There are a lot of explanations and specific examples above, but you can generalize N dimensional list of lists of lists of ... with the following recursive function:
import copy
def list_ndim(dim, el=None, init=None):
if init is None:
init = el
if len(dim)> 1:
return list_ndim(dim[0:-1], None, [copy.copy(init) for x in range(dim[-1])])
return [copy.deepcopy(init) for x in range(dim[0])]
You make your first call to the function like this:
dim = (3,5,2)
el = 1.0
l = list_ndim(dim, el)
where (3,5,2) is a tuple of the dimensions of the structure (similar to numpy shape argument), and 1.0 is the element you want the structure to be initialized with (works with None as well). Note that the init argument is only provided by the recursive call to carry forward the nested child lists
output of above:
[[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]]
set specific elements:
l[1][3][1] = 56
l[2][2][0] = 36.0+0.0j
l[0][1][0] = 'abc'
resulting output:
[[[1.0, 1.0], ['abc', 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 56.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 1.0], [(36+0j), 1.0], [1.0, 1.0], [1.0, 1.0]]]
the non-typed nature of lists is demonstrated above
While the original question constructed the sublists with the multiplication operator, I'll add an example that uses the same list for the sublists. Adding this answer for completeness as this question is often used as a canonical for the issue
node_count = 4
colors = [0,1,2,3]
sol_dict = {node:colors for node in range(0,node_count)}
The list in each dictionary value is the same object, trying to change one of the dictionaries values will be seen in all.
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> [v is colors for v in sol_dict.values()]
[True, True, True, True]
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 2, 3], 2: [0, 2, 3], 3: [0, 2, 3]}
The correct way to construct the dictionary would be to use a copy of the list for each value.
>>> colors = [0,1,2,3]
>>> sol_dict = {node:colors[:] for node in range(0,node_count)}
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
Note that items in the sequence are not copied; they are referenced multiple times. This often haunts new Python programmers; consider:
>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
What has happened is that [[]] is a one-element list containing an empty list, so all three elements of [[]] * 3 are references to this single empty list. Modifying any of the elements of lists modifies this single list.
Another example to explain this is using multi-dimensional arrays.
You probably tried to make a multidimensional array like this:
>>> A = [[None] * 2] * 3
This looks correct if you print it:
>>> A
[[None, None], [None, None], [None, None]]
But when you assign a value, it shows up in multiple places:
>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]
The reason is that replicating a list with * doesn’t create copies, it only creates references to the existing objects. The 3 creates a list containing 3 references to the same list of length two. Changes to one row will show in all rows, which is almost certainly not what you want.

Extract fixed number of elements per row in numpy array

Suppose I have an array a, and a boolean array b, I want to extract a fixed number of elements from the valid elements in each row of a. The valid elements are the ones indicated by b.
Here is an example:
a = np.arange(24).reshape(4,6)
b = np.array([[0,0,1,1,0,0],[0,1,0,1,0,1],[0,1,1,1,1,0],[0,0,0,0,1,1]]).astype(bool)
x = []
for i in range(a.shape[0]):
c = a[i,b[i]]
d = np.random.choice(c, 2)
x.append(d)
Here I used a for loop, which will be slow in case these arrays are big and high-dimensional. Is there a more efficient way to do this? Thanks.
Generate a random uniform [0, 1] matrix of shape a.
Multiply this matrix by the mask b to set invalid elements to zero.
Select the k maximum indices from each row (simulating an unbiased random k-sample from only the valid elements in this row).
(Optional) use these indices to get the elements.
a = np.arange(24).reshape(4,6)
b = np.array([[0,0,1,1,0,0],[0,1,0,1,0,1],[0,1,1,1,1,0],[0,0,0,0,1,1]])
k = 2
r = np.random.uniform(size=a.shape)
indices = np.argpartition(-r * b, k)[:,:k]
To get the elements from the indices:
>>> indices
array([[3, 2],
[5, 1],
[3, 2],
[4, 5]])
>>> a[np.arange(a.shape[0])[:,None], indices]
array([[ 3, 2],
[11, 7],
[15, 14],
[22, 23]])

NumPy: indexing array by list of tuples - how to do it correctly?

I am in the following situation - I have the following:
Multidimensional numpy array a of n dimensions
t, an array of k rows (tuples), each with n elements. In other words, each row in this array is an index in a
What I want: from a, return an array b with k scalar elements, the ith element in b being the result of indexing a with the ith tuple from t.
Seems trivial enough. The following approach, however, does not work
def get(a, t):
# wrong result + takes way too long
return a[t]
I have to resort to doing this iteratively i.e. the following works correctly:
def get(a, t):
res = []
for ind in t:
a_scalar = a
for i in ind:
a_scalar = a_scalar[i]
# a_scalar is now a scalar
res.append(a_scalar)
return res
This works, except for the fact that given that each dimension in a has over 30 elements, the procedure does get really slow when n gets to more than 5. I understand that it would be slow regardless, however, I would like to exploit numpy's capabilities as I believe it would speed up this process considerably.
The key to getting this right is to understand the roles of indexing lists and tuples. Often the two are treated the same, but in numpy indexing, tuples, list and arrays convey different information.
In [1]: a = np.arange(12).reshape(3,4)
In [2]: t = np.array([(0,0),(1,1),(2,2)])
In [4]: a
Out[4]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [5]: t
Out[5]:
array([[0, 0],
[1, 1],
[2, 2]])
You tried:
In [6]: a[t]
Out[6]:
array([[[ 0, 1, 2, 3],
[ 0, 1, 2, 3]],
[[ 4, 5, 6, 7],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[ 8, 9, 10, 11]]])
So what's wrong with it? It ran, but selected a (3,2) array of rows of a. That is, it applied t to just the first dimension, effectively a[t, :]. You want to index on all dimensions, some sort of a[t1, t2]. That's the same as a[(t1,t2)] - a tuple of indices.
In [10]: a[tuple(t[0])] # a[(0,0)]
Out[10]: 0
In [11]: a[tuple(t[1])] # a[(1,1)]
Out[11]: 5
In [12]: a[tuple(t[2])]
Out[12]: 10
or doing all at once:
In [13]: a[(t[:,0], t[:,1])]
Out[13]: array([ 0, 5, 10])
Another way to write it, is n lists (or arrays), one for each dimension:
In [14]: a[[0,1,2],[0,1,2]]
Out[14]: array([ 0, 5, 10])
In [18]: tuple(t.T)
Out[18]: (array([0, 1, 2]), array([0, 1, 2]))
In [19]: a[tuple(t.T)]
Out[19]: array([ 0, 5, 10])
More generally, in a[idx1, idx2] array idx1 is broadcast against idx2 to produce a full selection array. Here the 2 arrays are 1d and match, the selection is your t set of pairs. But the same principle applies to selecting a set of rows and columns, a[ [[0],[2]], [0,2,3] ].
Using the ideas in [10] and following, your get could be sped up with:
In [20]: def get(a, t):
...: res = []
...: for ind in t:
...: res.append(a[tuple(ind)]) # index all dimensions at once
...: return res
...:
In [21]: get(a,t)
Out[21]: [0, 5, 10]
If t really was a list of tuples (as opposed to an array built from them), your get could be:
In [23]: tl = [(0,0),(1,1),(2,2)]
In [24]: [a[ind] for ind in tl]
Out[24]: [0, 5, 10]
Explore using np.ravel_multi_index
Create some test data
arr = np.arange(10**4)
arr.shape=10,10,10,10
t = []
for j in range(5):
t.append( tuple(np.random.randint(10, size = 4)))
print(t)
# [(1, 8, 2, 0),
# (2, 3, 3, 6),
# (1, 4, 8, 5),
# (2, 2, 6, 3),
# (0, 5, 0, 2),]
ta = np.array(t).T
print(ta)
# array([[1, 2, 1, 2, 0],
# [8, 3, 4, 2, 5],
# [2, 3, 8, 6, 0],
# [0, 6, 5, 3, 2]])
arr.ravel()[np.ravel_multi_index(tuple(ta), (10,10,10,10))]
# array([1820, 2336, 1485, 2263, 502]
np.ravel_multi_index basically calculates, from the tuple of input arrays, the index into a flattened array that starts with shape (in this case) (10, 10, 10, 10).
Does this do what you need? Is it fast enough?

Assign 1 and 0 values to numpy array depending on whether values are in list

I am looking for a way to filter numpy arrays based on a list
input_array = [[0,4,6],[2,1,1],[6,6,9]]
list=[9,4]
...
output_array = [[0,1,0],[0,0,0],[0,0,1]]
I am currently flattening the array, and turning it to a list and back. Looks very unpythonic:
list=[9,4]
shape = input_array.shape
input_array = input_array.flatten()
output_array = np.array([int(i in list) for i in input_array])
output_array = output_array.reshape(shape)
We could use np.in1d to get the mask of matches. Now, np.in1d flattens the input to 1D before processing. So, the output from it is to be reshaped back to 2D and then converted to int for an output with 0s and 1s.
Thus, the implementation would be -
np.in1d(input_array, list).reshape(input_array.shape).astype(int)
Sample run -
In [40]: input_array
Out[40]:
array([[0, 4, 6],
[2, 1, 1],
[6, 6, 9]])
In [41]: list=[9,4]
In [42]: np.in1d(input_array, list).reshape(input_array.shape).astype(int)
Out[42]:
array([[0, 1, 0],
[0, 0, 0],
[0, 0, 1]])

Resources