Skip to content

ENH: Optimize np.unique with adaptive thresholding for hashing vs sorting#31970

Open
rajat315315 wants to merge 1 commit into
numpy:mainfrom
rajat315315:perf/optimize-np-unique
Open

ENH: Optimize np.unique with adaptive thresholding for hashing vs sorting#31970
rajat315315 wants to merge 1 commit into
numpy:mainfrom
rajat315315:perf/optimize-np-unique

Conversation

@rajat315315

Copy link
Copy Markdown

Closes: #31969

Proposed Changes

This PR implements adaptive thresholding for np.unique to select the most efficient pathway (hashing vs sorting) based on the input dtype and size:

  • StringDType: Always routed to _unique_hash as hashing variable-width strings remains faster than sorting.
  • All other dtypes (numeric, complex, fixed-width unicode): Routed to _unique_hash only if the array size is < 100 elements (where Python/C setup overhead of sorting dominates). For larger sizes, it directly uses the SIMD-accelerated sorting-based unique pathway.

Benchmarks (1,000,000 elements)

Dtype / Scenario Before (ms) After (ms) Speedup Pathway Used
int64 (All unique) 712.6 ms 15.2 ms 46x Sorting (After) vs Hashing (Before)
int64 (10 unique) 45.7 ms 15.8 ms 2.9x Sorting (After) vs Hashing (Before)
'U15' (Distinct strings) 99.4 ms 12.2 ms 8.1x Sorting (After) vs Hashing (Before)
StringDType (1M repeated) 99.5 ms 99.5 ms 1.0x Hashing (Unchanged)

Benchmarks (10 elements)

Dtype Before (us) After (us) Speedup Pathway Used
int64 6.0 us 6.0 us 1.0x Hashing (Unchanged)

Verification

All set operation tests pass:

pytest numpy/lib/tests/test_arraysetops.py

Output: 117 passed in 0.73s

First time committer introduction

I use it a lot for data chuking.

AI Disclosure

Used Gemini 3.1 Pro in benchmarking the results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PERF: np.unique has massive performance regression for large numeric arrays due to _unique_hash

2 participants