Skip to content

Commit 6809d6a

Browse files
[Autoloop: perf-comparison] Iteration 414: add categorical_ops benchmarks
Benchmarks catFromCodes, catSortByFreq, catFreqTable, and catCrossTab vs pandas equivalents (Categorical.from_codes, value_counts, crosstab). Dataset: 100k rows, 5 categories (TS) vs 3 categories (crossTab). Run: https://github.com/githubnext/tsb/actions/runs/29834097853 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9aff1e6 commit 6809d6a

2 files changed

Lines changed: 121 additions & 0 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""Benchmark: categorical operations on 100k-element Series
2+
3+
Covers pd.Categorical.from_codes, value_counts (sort by freq), and pd.crosstab.
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
ROWS = 100_000
11+
WARMUP = 3
12+
ITERATIONS = 10
13+
14+
# Build a categorical Series from codes + categories
15+
CATEGORIES = ["alpha", "beta", "gamma", "delta", "epsilon"]
16+
codes = np.arange(ROWS) % len(CATEGORIES)
17+
cat_series = pd.Series(pd.Categorical.from_codes(codes, categories=CATEGORIES))
18+
19+
# Build a second categorical for crosstab
20+
CATEGORIES2 = ["x", "y", "z"]
21+
codes2 = np.arange(ROWS) % len(CATEGORIES2)
22+
cat_series2 = pd.Series(pd.Categorical.from_codes(codes2, categories=CATEGORIES2))
23+
24+
# Warm up
25+
for _ in range(WARMUP):
26+
cat_series.value_counts()
27+
cat_series.value_counts(sort=True)
28+
pd.crosstab(cat_series, cat_series2)
29+
30+
# Measure value_counts (analogous to catFreqTable)
31+
start = time.perf_counter()
32+
for _ in range(ITERATIONS):
33+
cat_series.value_counts(sort=False)
34+
freq_table_ms = (time.perf_counter() - start) * 1000 / ITERATIONS
35+
36+
# Measure value_counts sorted by freq (analogous to catSortByFreq)
37+
start = time.perf_counter()
38+
for _ in range(ITERATIONS):
39+
cat_series.value_counts(sort=True)
40+
sort_by_freq_ms = (time.perf_counter() - start) * 1000 / ITERATIONS
41+
42+
# Measure crosstab (analogous to catCrossTab)
43+
start = time.perf_counter()
44+
for _ in range(ITERATIONS):
45+
pd.crosstab(cat_series, cat_series2)
46+
cross_tab_ms = (time.perf_counter() - start) * 1000 / ITERATIONS
47+
48+
mean_ms = (freq_table_ms + sort_by_freq_ms + cross_tab_ms) / 3
49+
50+
print(json.dumps({
51+
"function": "categorical_ops",
52+
"mean_ms": mean_ms,
53+
"iterations": ITERATIONS,
54+
"total_ms": mean_ms * ITERATIONS,
55+
"details": {
56+
"freqTableMs": freq_table_ms,
57+
"sortByFreqMs": sort_by_freq_ms,
58+
"crossTabMs": cross_tab_ms,
59+
},
60+
}))
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Benchmark: categorical operations on 100k-element Series
3+
*
4+
* Covers catFromCodes, catSortByFreq, catFreqTable, and catCrossTab.
5+
*/
6+
import { Series, catFromCodes, catSortByFreq, catFreqTable, catCrossTab } from "../../src/index.js";
7+
8+
const ROWS = 100_000;
9+
const WARMUP = 3;
10+
const ITERATIONS = 10;
11+
12+
// Build a categorical Series from codes + categories
13+
const CATEGORIES = ["alpha", "beta", "gamma", "delta", "epsilon"];
14+
const codes = Int32Array.from({ length: ROWS }, (_, i) => i % CATEGORIES.length);
15+
16+
const catSeries = catFromCodes(Array.from(codes), CATEGORIES);
17+
18+
// Build a second categorical for crossTab
19+
const CATEGORIES2 = ["x", "y", "z"];
20+
const codes2 = Int32Array.from({ length: ROWS }, (_, i) => i % CATEGORIES2.length);
21+
const catSeries2 = catFromCodes(Array.from(codes2), CATEGORIES2);
22+
23+
// Warm up
24+
for (let i = 0; i < WARMUP; i++) {
25+
catSortByFreq(catSeries);
26+
catFreqTable(catSeries);
27+
catCrossTab(catSeries, catSeries2);
28+
}
29+
30+
// Measure catSortByFreq
31+
let start = performance.now();
32+
for (let i = 0; i < ITERATIONS; i++) {
33+
catSortByFreq(catSeries);
34+
}
35+
const sortByFreqMs = (performance.now() - start) / ITERATIONS;
36+
37+
// Measure catFreqTable
38+
start = performance.now();
39+
for (let i = 0; i < ITERATIONS; i++) {
40+
catFreqTable(catSeries);
41+
}
42+
const freqTableMs = (performance.now() - start) / ITERATIONS;
43+
44+
// Measure catCrossTab
45+
start = performance.now();
46+
for (let i = 0; i < ITERATIONS; i++) {
47+
catCrossTab(catSeries, catSeries2);
48+
}
49+
const crossTabMs = (performance.now() - start) / ITERATIONS;
50+
51+
const mean_ms = (sortByFreqMs + freqTableMs + crossTabMs) / 3;
52+
53+
console.log(
54+
JSON.stringify({
55+
function: "categorical_ops",
56+
mean_ms,
57+
iterations: ITERATIONS,
58+
total_ms: mean_ms * ITERATIONS,
59+
details: { sortByFreqMs, freqTableMs, crossTabMs },
60+
}),
61+
);

0 commit comments

Comments
 (0)