Skip to content

Commit be070de

Browse files
jbrockmendelclaude
andauthored
PERF: restore kh_get before kh_put in hashtable operations (pandas-dev#65026)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 01904bb commit be070de

2 files changed

Lines changed: 31 additions & 24 deletions

File tree

pandas/_libs/hashtable_class_helper.pxi.in

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -757,10 +757,11 @@ cdef class {{name}}HashTable(HashTable):
757757
append_data_uint8(rmd, 1)
758758
continue
759759

760-
k = kh_put_{{dtype}}(self.table, val, &ret)
760+
k = kh_get_{{dtype}}(self.table, val)
761761

762-
if ret != 0:
762+
if k == self.table.n_buckets:
763763
# k hasn't been seen yet
764+
k = kh_put_{{dtype}}(self.table, val, &ret)
764765

765766
if needs_resize(ud.size, ud.capacity):
766767
with gil:
@@ -898,8 +899,12 @@ cdef class {{name}}HashTable(HashTable):
898899
labels[i] = -1
899900
continue
900901

901-
k = kh_put_{{dtype}}(self.table, val, &ret)
902-
if ret != 0:
902+
k = kh_get_{{dtype}}(self.table, val)
903+
if k != self.table.n_buckets:
904+
idx = self.table.vals[k]
905+
labels[i] = idx
906+
else:
907+
k = kh_put_{{dtype}}(self.table, val, &ret)
903908
self.table.vals[k] = count
904909

905910
if needs_resize(ud.size, ud.capacity):
@@ -908,9 +913,6 @@ cdef class {{name}}HashTable(HashTable):
908913
append_data_{{dtype}}(ud, val)
909914
labels[i] = count
910915
count += 1
911-
else:
912-
idx = self.table.vals[k]
913-
labels[i] = idx
914916

915917
arr_uniques = uniques.to_array()
916918

@@ -1219,9 +1221,10 @@ cdef class StringHashTable(HashTable):
12191221
continue
12201222

12211223
v = vecs[i]
1222-
k = kh_put_str(self.table, v, &ret)
1223-
if ret != 0:
1224+
k = kh_get_str(self.table, v)
1225+
if k == self.table.n_buckets:
12241226
# k hasn't been seen yet
1227+
k = kh_put_str(self.table, v, &ret)
12251228
uindexer[count] = i
12261229
if return_inverse:
12271230
self.table.vals[k] = count
@@ -1491,9 +1494,10 @@ cdef class PyObjectHashTable(HashTable):
14911494
labels[i] = na_sentinel
14921495
continue
14931496

1494-
k = kh_put_pymap(self.table, <PyObject*>val, &ret)
1495-
if ret != 0:
1497+
k = kh_get_pymap(self.table, <PyObject*>val)
1498+
if k == self.table.n_buckets:
14961499
# k hasn't been seen yet
1500+
k = kh_put_pymap(self.table, <PyObject*>val, &ret)
14971501
uniques.append(val)
14981502
if return_inverse:
14991503
self.table.vals[k] = count

pandas/_libs/hashtable_func_helper.pxi.in

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,13 @@ cdef value_count_{{dtype}}(const {{dtype}}_t[:] values, bint dropna, const uint8
6666
for i in range(n):
6767
val = values[i]
6868
if not dropna or not checknull(val):
69-
k = kh_put_{{ttype}}(table, {{to_c_type}}val, &ret)
70-
if ret != 0:
69+
k = kh_get_{{ttype}}(table, {{to_c_type}}val)
70+
if k != table.n_buckets:
71+
table.vals[k] += 1
72+
else:
73+
k = kh_put_{{ttype}}(table, {{to_c_type}}val, &ret)
7174
table.vals[k] = 1
7275
result_keys.append(val)
73-
else:
74-
table.vals[k] += 1
7576
{{else}}
7677
kh_resize_{{ttype}}(table, n)
7778

@@ -89,12 +90,13 @@ cdef value_count_{{dtype}}(const {{dtype}}_t[:] values, bint dropna, const uint8
8990
if uses_mask and isna_entry:
9091
na_counter += 1
9192
else:
92-
k = kh_put_{{ttype}}(table, val, &ret)
93-
if ret != 0:
93+
k = kh_get_{{ttype}}(table, val)
94+
if k != table.n_buckets:
95+
table.vals[k] += 1
96+
else:
97+
k = kh_put_{{ttype}}(table, val, &ret)
9498
table.vals[k] = 1
9599
result_keys.append(val)
96-
else:
97-
table.vals[k] += 1
98100
{{endif}}
99101

100102
# collect counts in the order corresponding to result_keys:
@@ -191,13 +193,14 @@ cdef duplicated_{{dtype}}(const {{dtype}}_t[:] values, object keep='first', cons
191193

192194
else:
193195
value = {{to_c_type}}(values[i])
194-
k = kh_put_{{ttype}}(table, value, &ret)
195-
if ret != 0:
196-
table.vals[k] = i
197-
out[i] = 0
198-
else:
196+
k = kh_get_{{ttype}}(table, value)
197+
if k != table.n_buckets:
199198
out[table.vals[k]] = 1
200199
out[i] = 1
200+
else:
201+
k = kh_put_{{ttype}}(table, value, &ret)
202+
table.vals[k] = i
203+
out[i] = 0
201204

202205
kh_destroy_{{ttype}}(table)
203206
return out

0 commit comments

Comments
 (0)