0

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]]
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
Ami
  • 3
  • 2

3 Answers3

1

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[tuple(zip(*i))] = 1
Reti43
  • 9,656
  • 3
  • 28
  • 44
  • It raises FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]` – mathfux Dec 05 '21 at 05:03
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.]]
LevB
  • 925
  • 6
  • 10
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)
mathfux
  • 5,759
  • 1
  • 14
  • 34