4

I have a numpy array

src = np.random.rand(320,240)

and another numpy array idx of size (2 x (320*240)). Each column of idx indexes an entry in a result array dst, e.g., idx[:,20] = [3,10] references row 3, column 10 in dst and the assumption is that 20 corresponds to the flattened index of src, i.e., idx establishes a mapping between the entries of src and dst. Assuming dst is initialized with all zeros, how can I copy the entries in src to their destination in dst without a loop?

3

2 Answers 2

3

Here is the canonical way of doing it:

>>> import numpy as np
>>> 
>>> src = np.random.rand(4, 3)
>>> src
array([[0.0309325 , 0.72261479, 0.98373595],
       [0.06357406, 0.44763809, 0.45116039],
       [0.63992938, 0.6445605 , 0.01267776],
       [0.76084312, 0.61888759, 0.2138713 ]])
>>> 
>>> idx = np.indices(src.shape).reshape(2, -1)
>>> np.random.shuffle(idx.T)
>>> idx
array([[3, 3, 0, 1, 0, 3, 1, 1, 2, 2, 2, 0],
       [1, 2, 2, 0, 1, 0, 1, 2, 2, 1, 0, 0]])
>>> 
>>> dst = np.empty_like(src)
>>> dst[tuple(idx)] = src.ravel()
>>> dst
array([[0.2138713 , 0.44763809, 0.98373595],
       [0.06357406, 0.63992938, 0.6445605 ],
       [0.61888759, 0.76084312, 0.01267776],
       [0.45116039, 0.0309325 , 0.72261479]])

If you can't be sure that idx is a proper shuffle it's a bit safer to use np.full with a fill value that does not appear in src instead of np.empty.

>>> dst = np.full_like(src, np.nan)
>>> dst[tuple(idx)] = src.ravel()
>>> 
>>> dst
array([[0.27020869, 0.71216066,        nan],
       [0.63812283, 0.69151451, 0.65843901],
       [       nan, 0.02406174, 0.47543061],
       [0.05650845,        nan,        nan]])

If you spot the fill value in dst, something is wrong with idx.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, exactly what I was looking for! Actually, it is quite possible in my case that indices may appear multiple times in idx (and others do not at all). In your version, the number appearing in dst would be the one corresponding to the last appearance of the index in idx, right? Is it possible to control this behavior based on a precedence array p, i.e., if an index appears twice copy the entry whose precedence in p is higher? (if you are curious, this is for multi-view geometry in a renderer)
Officially, For advanced assignments, there is in general no guarantee for the iteration order. This means that if an element is set more than once, it is not possible to predict the final result. I'm not aware of a quick fix for the precedence. Why don't you make a new question, I think it is an interesting problem.
1

You can try:

dst[idx[0, :], idx[1, :]] = src.flat

In [33]: src = np.random.randn(2, 3)

In [34]: src
Out[34]: 
array([[ 0.68636938,  0.60275041,  1.26078727],
       [ 1.17937849, -1.0369404 ,  0.42847611]])

In [35]: dst = np.zeros_like(src)

In [37]: idx = np.array([[0, 1, 0, 1, 0, 0], [1, 2, 0, 1, 2, 0]])

In [38]: dst[idx[0, :], idx[1, :]] = src.flat

In [39]: dst
Out[39]: 
array([[ 0.42847611,  0.68636938, -1.0369404 ],
       [ 0.        ,  1.17937849,  0.60275041]])

dst[0, 1] is src[0, 0], etc.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.