1
votes

I would like to translate arbitrary integers in a numpy array to a contiguous range 0...n, like this:

source: [2 3 4 5 4 3]
translating [2 3 4 5] -> [0 1 2 3]
target: [0 1 2 3 2 1]

There must be a better way to than the following:

import numpy as np

"translate arbitrary integers in the source array to contiguous range 0...n"

def translate_ids(source, source_ids, target_ids):
    target = source.copy()

    for i in range(len(source_ids)):
        x = source_ids[i]
        x_i = source == x
        target[x_i] = target_ids[i]

    return target

#

source = np.array([ 2, 3, 4, 5, 4, 3 ])
source_ids = np.unique(source)
target_ids = np.arange(len(source_ids))

target = translate_ids(source, source_ids, target_ids)

print "source:", source
print "translating", source_ids, '->', target_ids
print "target:", target

What is it?

2

2 Answers

4
votes

IIUC you can simply use np.unique's optional argument return_inverse, like so -

np.unique(source,return_inverse=True)[1]

Sample run -

In [44]: source
Out[44]: array([2, 3, 4, 5, 4, 3])

In [45]: np.unique(source,return_inverse=True)[1]
Out[45]: array([0, 1, 2, 3, 2, 1])
1
votes

pandas.factorize is one method:

import pandas as pd

lst = [2, 3, 4, 5, 4, 3]
res = pd.factorize(lst, sort=True)[0]

# [0 1 2 3 2 1]

Note: this returns a list, while np.unique will always return an np.ndarray.