I have two lists of integer values of the same length: a list of items and a list of labels. If an item is duplicated in the list of items, that means they are labeled using different integers in the list of labels. I want to to assign the same integer/label (e.g. the label of the first occurrence) to all of the items that are labeled with those integers (note that this can be more than just the duplicates we first found in the list of items).
Here is a minimal example of what I am doing (I converted the lists to arrays):
import numpy as np
import numba as nb
from collections import Counter
items = np.array([7,2,0,6,0,4,1,5,2,0])
labels = np.array([1,0,3,4,2,1,6,6,5,4])
dups = [x for x, c in Counter(items).items() if c>1]
#@nb.njit(fastmath=True)
def update_labels(items, labels, dups):
for dup in dups:
found = np.where(items==dup)[0]
l = labels[found]
isin = np.where((np.isin(labels, l)))[0]
labels[isin] = labels[isin[0]]
return labels
new_labels = update_labels(items, labels, dups)
print(new_labels) # prints [1 0 3 3 3 1 6 6 0 3]
The code works fine for small lists. However, for larger lists like
np.random.seed(0)
n = 1_000_000
items = np.random.randint(n, size=n)
labels = np.random.randint(int(0.8*n), size=n)
it takes forever to return the new labels. The bottleneck is in the update_labels() function which I also tried to accelerate by using a numba jit decorator but it turns out that np.isin is not supported by numba.
Is there any way to make this algorithm more efficient and/or get it to work (efficiently) with numba? The code efficiency is extremely important to me since I use this with huge lists (tens of millions). I am also open to use a C or C++ function and call it from Python as a last resort. I use Python 3.x.