简体   繁体   中英

how to change element of matrix by a list of index

how to change element of array according to a list of index Suppose I have

z = np.zeros([3, 3])
i = [[1, 1], [2, 0], [0, 2]]

where each element in i is an index of z, and i would like to change the corresponding element in z to be 1 obtain:

[[0, 0, 1], [0, 1, 0], [1, 0, 0]]

and i cannot use loop, since i actually have a much larger matrix than z. I try to use np.put, but it return

[[1, 1, 1], [0, 0, 0], [0, 0, 0]]

Numpy's indexing means you can select multiple elements if you group the row coordinates and the column coordinates (or however many axes you may have) separately. Basically you want [[1, 2, 0], [1, 0, 2]] , which is the transpose of your list of lists.

z[[*zip(*i)]] = 1

For multidimensional indexing, you have to use a tuple now. Any other sequence format is being deprecated, so:

z[tuple(zip(*i))] = 1
print(z)

Output:

[[0. 0. 1.]
 [0. 1. 0.]
 [1. 0. 0.]]

You might want to set up your coordinates as an array rather than a list.

z = np.zeros([3, 3])
i = np.array([[1, 1], [2, 0], [0, 2]])

z[tuple(i.T)] = 1

print(z)

Output:

[[0. 0. 1.]
 [0. 1. 0.]
 [1. 0. 0.]]

It depends a lot on data type of i .

If you're able to store i as array, it's better to use np.transpose instead of zip:

z = np.zeros([3, 3])
i = np.array([[1, 1], [2, 0], [0, 2]])
x, y = np.transpose(i)
z[x, y] = 1

It will change its view and that's costless. You need to unpack only two arguments x and y which is near costless too.

In comparison, zip creates a generator for Python - style iteration of every item in i which is more expensive:

z = np.zeros([3, 3])
i = [[1, 1], [2, 0], [0, 2]]
x, y = z[tuple(zip(*i))] = 1
z[x, y] = 1

The worst thing you can do is to call zip on numpy array because they are not designed for fast iteration.

There are some test that demonstrates advantages and disadvantages of zip vs np.transpose :

z = np.zeros([3000, 3000])
ii = np.random.randint(3000, size=(1500000, 2))
i = ii.tolist()

%%timeit
x, y = np.transpose(i) #lots of time spent for conversion into arr
z[x, y] = 1
3.07 s ± 32.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
x, y = np.transpose(ii)
z[x, y] = 1
106 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
z[tuple(zip(*i))] = 1
1.26 s ± 14.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM