3

In a given array I want to replace the values by the index of this value in an other array (which doesn't contain duplicates). Here is a simple example of I'm trying to do:

import numpy as np
from copy import deepcopy

a = np.array([[0, 1, 2], [2, 1, 3], [0, 1, 3]])
chg = np.array([3, 0, 2, 1])

b = deepcopy(a)
for new, old  in enumerate(chg):
   b[a == old] = new

print b
# [[1 3 2] [2 3 0] [1 3 0]]

But I need to do that on large arrays so having an explicit loop is not acceptable in terms of execution time.

I can't figure out how to do that using fancy numpy functions...

10
  • 1
    I dont understand what you are trying to do... Commented Oct 26, 2015 at 15:08
  • 1
    @JoranBeasley: To me it looks like he's taking the values in a, finding their index in chg and creating a new structure b that holds the indexes. Commented Oct 26, 2015 at 15:11
  • Also don't understand this. I don't think the code is doing what the OP expects. By the way you can just do b = a.copy()... Commented Oct 26, 2015 at 15:13
  • @YXD: Regarding using a.copy, I believe modifying the subarrays would modify the original array without deepcopy. Commented Oct 26, 2015 at 15:14
  • 1
    @StevenRumbalski it doesn't: a = np.arange(5); b = a.copy(); b[0] = 7; print(a) - a is not modified Commented Oct 26, 2015 at 15:16

4 Answers 4

2

take is your friend.

a = np.array([[0, 1, 2], [2, 1, 3], [0, 1, 3]])
chg = np.array([3, 0, 2, 1])
inverse_chg=chg.take(chg)
print(inverse_chg.take(a))

gives :

[[1 3 2]
 [2 3 0]
 [1 3 0]]

or more directly with fancy indexing: chg[chg][a], but inverse_chg.take(a) is three times faster.

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

1 Comment

Cool use of take (+1) but this might break if chg = np.array([4, 0, 2, 1]), for example.
2

You can convert chg to a 3D array by adding two new axes at the end of it and then perform the matching comparison with a, which would bring in NumPy's broadcasting to give us a 3D mask. Next up, get the argmax on the mask along the first axis to simulate "b[a == old] = new". Finally, replace the ones that had no matches along that axis with the corresponding values in a. The implementation would look something like this -

mask = a == chg[:,None,None]
out = mask.argmax(0)
invalid_pos = ~mask.max(0)
out[invalid_pos] = a[invalid_pos]

Comments

2

This type of replacement operation can be tricky to do in full generality with NumPy, although you could use searchsorted:

>>> s = np.argsort(chg)
>>> s[np.searchsorted(chg, a.ravel(), sorter=s).reshape(a.shape)]
array([[1, 3, 2],
       [2, 3, 0],
       [1, 3, 0]])

(Note: searchsorted doesn't just replace exact matches, so be careful if you have values in a that aren't in chg...)

pandas has a variety of tools which can make these operations on NumPy arrays much easier and potentially a lot quicker / more memory efficient for larger arrays. For this specific problem, pd.match could be used:

>>> pd.match(a.ravel(), chg).reshape(a.shape)
array([[1, 3, 2],
       [2, 3, 0],
       [1, 3, 0]])

This function also allows you to specify what value should be filled if a value is missing from chg.

3 Comments

Good to see searchsorted! Guess not for cases like chg = np.array([4, 0, 2, 1])? But since OP accepted .take that assumes the same, maybe this would work for OP too.
@Divakar: thanks - this should actually work for the cases like chg = np.array([4, 0, 2, 1]), although I should probably caveat the answer by saying that searchsorted doesn't look for exact matches, so it might replace values in a that don't exist in chg.
Yeah well, if chg has all the values that exist in a, this might just be the fastest.
-2

Check this out:

a = np.array([3,4,1,2,0])
b = np.array([[0,0],[0,1],[0,2],[0,3],[0,4]])

c = b[a]
print(c)

It gives me back:

[[0 3]
 [0 4]
 [0 1]
 [0 2]
 [0 0]]

If you're working with numpy arrays you could do this.

1 Comment

I'm not sure you understood what I'm trying to do... cause this is just a reordering of your array that you are doing.

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.