cp.unique without sorting
Description
There are use cases where one wants to find unique rows in a 2D array without having to sort the outputs. This is already recognized by the implementation of unique by pandas. They claim it to be significantly faster than numpy's for long enough sequences.
I wanted to try the differences by implementing such functionality, keeping numpy's API. So I tried:
@numba.njit('Tuple((int64[::1], int64[::1], int32[::1]))(int64[::1])')
def _unique1d_with_no_sort_cpu_kernel(arr):
uniques = dict()
counts = dict()
INF64 = np.iinfo(np.int64).max
ind = np.ones(arr.size, dtype=np.int64) * INF64
inv = np.empty(arr.size, dtype=np.int64)
count_unique = -1
for i, row in enumerate(arr):
if row not in uniques:
count_unique += 1
uniques[row] = count_unique
counts[row] = 1
ind[count_unique] = i
else:
counts[row] += 1
inv[i] = uniques[row]
counts = np.asarray(list(counts.values()), dtype=np.int32)
return ind[ind != INF64], inv, countsand then wrap it by
def unique_no_sort_cpu_axis0(arr):
arr_hashed = np.asarray([hash(row.tobytes()) for row in arr])
return _unique1d_with_no_sort_cpu_kernel(arr_hashed)Write a test case:
arr = np.random.randint(0, 2, (1000000, 10))
a1, b1, c1 = unique_no_sort_cpu_axis0(arr)
_, a2, b2, c2 = np.unique(
arr,
return_index=True,
return_inverse=True,
return_counts=True,
axis=0
)Asserting equality:
>>> all([np.all(a1==a2), np.all(b1==b2), np.all(c1==c2)])
TrueCompare performance:
>>> %timeit unique_no_sort_cpu_axis0(arr)
273 ms ± 452 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit np.unique(arr, return_index=True, return_inverse=True, return_counts=True, axis=0)
2.27 s ± 49.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)This implementation is then ~8x faster than numpy.
Since finding unique rows using cupy is also of interest (e.g. see the latest post requesting such a feature, which is btw already possible by sorting), I am very interested in the possibility of a faster implementation without sorting. Could you please consider it?
Many thanks in advance.
Additional Information
No response
Source: cupy/cupy