Skip to content

Commit 3165c28

Browse files
Iteration 137: Add 8 benchmark pairs (404 total, +8 vs 396)
Added pairs: infer_dtype, value_counts_binned, categorical_index, tz_localize_convert, align_series, align_dataframe, memory_usage, named_agg. Covers dtype inference, binned value counts, CategoricalIndex ops, timezone operations, Series/DataFrame alignment, memory estimation, and named aggregation (lost in iter 133's missing branch). Run: https://github.com/githubnext/tsessebe/actions/runs/24537885791 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9191c69 commit 3165c28

16 files changed

Lines changed: 652 additions & 0 deletions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Benchmark: DataFrame.align — align two 10k-row DataFrames on inner/outer/left join.
3+
Outputs JSON: {"function": "align_dataframe", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
SIZE = 10_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
idx_a = [i * 2 for i in range(SIZE)]
15+
idx_b = [i * 3 for i in range(SIZE)]
16+
17+
df_a = pd.DataFrame(
18+
{"x": [i * 1.0 for i in range(SIZE)], "y": [i * 2.0 for i in range(SIZE)], "z": [i * 3.0 for i in range(SIZE)]},
19+
index=idx_a,
20+
)
21+
df_b = pd.DataFrame(
22+
{"y": [i * 10.0 for i in range(SIZE)], "z": [i * 20.0 for i in range(SIZE)], "w": [i * 30.0 for i in range(SIZE)]},
23+
index=idx_b,
24+
)
25+
26+
for _ in range(WARMUP):
27+
df_a.align(df_b, join="inner")
28+
df_a.align(df_b, join="outer")
29+
df_a.align(df_b, join="left")
30+
31+
start = time.perf_counter()
32+
for _ in range(ITERATIONS):
33+
df_a.align(df_b, join="inner")
34+
df_a.align(df_b, join="outer")
35+
df_a.align(df_b, join="left")
36+
total = (time.perf_counter() - start) * 1000
37+
38+
print(json.dumps({
39+
"function": "align_dataframe",
40+
"mean_ms": total / ITERATIONS,
41+
"iterations": ITERATIONS,
42+
"total_ms": total,
43+
}))
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
Benchmark: Series.align — align two 50k-element Series on inner/outer/left join.
3+
Outputs JSON: {"function": "align_series", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
SIZE = 50_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
idx_a = [i * 2 for i in range(SIZE)]
15+
idx_b = [i * 3 for i in range(SIZE)]
16+
s_a = pd.Series([i * 1.0 for i in range(SIZE)], index=idx_a)
17+
s_b = pd.Series([i * 2.0 for i in range(SIZE)], index=idx_b)
18+
19+
for _ in range(WARMUP):
20+
s_a.align(s_b, join="inner")
21+
s_a.align(s_b, join="outer")
22+
s_a.align(s_b, join="left")
23+
24+
start = time.perf_counter()
25+
for _ in range(ITERATIONS):
26+
s_a.align(s_b, join="inner")
27+
s_a.align(s_b, join="outer")
28+
s_a.align(s_b, join="left")
29+
total = (time.perf_counter() - start) * 1000
30+
31+
print(json.dumps({
32+
"function": "align_series",
33+
"mean_ms": total / ITERATIONS,
34+
"iterations": ITERATIONS,
35+
"total_ms": total,
36+
}))
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
Benchmark: pandas.CategoricalIndex — creation, get_loc, add_categories, set operations on 100k elements.
3+
Outputs JSON: {"function": "categorical_index", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
CATS = ["alpha", "beta", "gamma", "delta", "epsilon"]
15+
labels = [CATS[i % len(CATS)] for i in range(SIZE)]
16+
ci = pd.CategoricalIndex(labels)
17+
labels2 = [CATS[(i + 2) % len(CATS)] for i in range(SIZE // 2)]
18+
ci2 = pd.CategoricalIndex(labels2)
19+
20+
for _ in range(WARMUP):
21+
pd.CategoricalIndex(labels)
22+
ci.get_loc("beta")
23+
ci.add_categories(["zeta"])
24+
ci.union(ci2)
25+
ci.intersection(ci2)
26+
27+
start = time.perf_counter()
28+
for _ in range(ITERATIONS):
29+
pd.CategoricalIndex(labels)
30+
ci.get_loc("beta")
31+
ci.add_categories(["zeta"])
32+
ci.union(ci2)
33+
ci.intersection(ci2)
34+
total = (time.perf_counter() - start) * 1000
35+
36+
print(json.dumps({
37+
"function": "categorical_index",
38+
"mean_ms": total / ITERATIONS,
39+
"iterations": ITERATIONS,
40+
"total_ms": total,
41+
}))
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Benchmark: infer_dtype — pandas.api.types.infer_dtype on 100k-element arrays.
3+
Outputs JSON: {"function": "infer_dtype", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
from pandas.api.types import infer_dtype
10+
11+
SIZE = 100_000
12+
WARMUP = 5
13+
ITERATIONS = 50
14+
15+
int_arr = list(range(SIZE))
16+
float_arr = [i * 0.5 for i in range(SIZE)]
17+
str_arr = [f"val_{i}" for i in range(SIZE)]
18+
mixed_arr = [f"s{i}" if i % 3 == 0 else i for i in range(SIZE)]
19+
20+
for _ in range(WARMUP):
21+
infer_dtype(int_arr, skipna=True)
22+
infer_dtype(float_arr, skipna=True)
23+
infer_dtype(str_arr, skipna=True)
24+
infer_dtype(mixed_arr, skipna=True)
25+
26+
start = time.perf_counter()
27+
for _ in range(ITERATIONS):
28+
infer_dtype(int_arr, skipna=True)
29+
infer_dtype(float_arr, skipna=True)
30+
infer_dtype(str_arr, skipna=True)
31+
infer_dtype(mixed_arr, skipna=True)
32+
total = (time.perf_counter() - start) * 1000
33+
34+
print(json.dumps({
35+
"function": "infer_dtype",
36+
"mean_ms": total / ITERATIONS,
37+
"iterations": ITERATIONS,
38+
"total_ms": total,
39+
}))
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Benchmark: Series.memory_usage / DataFrame.memory_usage — memory estimation.
3+
Outputs JSON: {"function": "memory_usage", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 50
13+
14+
num_series = pd.Series([i * 1.0 for i in range(SIZE)])
15+
str_series = pd.Series([f"label_{i % 100}" for i in range(SIZE)])
16+
df = pd.DataFrame({
17+
"a": [i * 1.0 for i in range(SIZE)],
18+
"b": [i * 2.0 for i in range(SIZE)],
19+
"c": [f"cat_{i % 50}" for i in range(SIZE)],
20+
"d": [i % 2 == 0 for i in range(SIZE)],
21+
})
22+
23+
for _ in range(WARMUP):
24+
num_series.memory_usage()
25+
str_series.memory_usage(deep=True)
26+
df.memory_usage()
27+
df.memory_usage(deep=True)
28+
29+
start = time.perf_counter()
30+
for _ in range(ITERATIONS):
31+
num_series.memory_usage()
32+
str_series.memory_usage(deep=True)
33+
df.memory_usage()
34+
df.memory_usage(deep=True)
35+
total = (time.perf_counter() - start) * 1000
36+
37+
print(json.dumps({
38+
"function": "memory_usage",
39+
"mean_ms": total / ITERATIONS,
40+
"iterations": ITERATIONS,
41+
"total_ms": total,
42+
}))
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Benchmark: DataFrameGroupBy.agg with named aggregations (pandas.NamedAgg) on 100k rows.
3+
Outputs JSON: {"function": "named_agg", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 20
13+
14+
depts = ["eng", "hr", "sales", "finance", "ops"]
15+
df = pd.DataFrame({
16+
"dept": [depts[i % len(depts)] for i in range(SIZE)],
17+
"salary": [50_000 + (i % 100) * 1000 for i in range(SIZE)],
18+
"headcount": [1 + (i % 5) for i in range(SIZE)],
19+
"score": [(i % 100) * 0.1 for i in range(SIZE)],
20+
})
21+
22+
gb = df.groupby("dept")
23+
24+
for _ in range(WARMUP):
25+
gb.agg(
26+
total_salary=pd.NamedAgg(column="salary", aggfunc="sum"),
27+
avg_salary=pd.NamedAgg(column="salary", aggfunc="mean"),
28+
max_salary=pd.NamedAgg(column="salary", aggfunc="max"),
29+
employees=pd.NamedAgg(column="headcount", aggfunc="count"),
30+
avg_score=pd.NamedAgg(column="score", aggfunc="mean"),
31+
)
32+
33+
start = time.perf_counter()
34+
for _ in range(ITERATIONS):
35+
gb.agg(
36+
total_salary=pd.NamedAgg(column="salary", aggfunc="sum"),
37+
avg_salary=pd.NamedAgg(column="salary", aggfunc="mean"),
38+
max_salary=pd.NamedAgg(column="salary", aggfunc="max"),
39+
employees=pd.NamedAgg(column="headcount", aggfunc="count"),
40+
avg_score=pd.NamedAgg(column="score", aggfunc="mean"),
41+
)
42+
total = (time.perf_counter() - start) * 1000
43+
44+
print(json.dumps({
45+
"function": "named_agg",
46+
"mean_ms": total / ITERATIONS,
47+
"iterations": ITERATIONS,
48+
"total_ms": total,
49+
}))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Benchmark: DatetimeIndex.tz_localize / tz_convert — timezone operations on 10k-element index.
3+
Outputs JSON: {"function": "tz_localize_convert", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
9+
SIZE = 10_000
10+
WARMUP = 5
11+
ITERATIONS = 50
12+
13+
naive = pd.date_range(start="2024-01-01", periods=SIZE, freq="h")
14+
15+
for _ in range(WARMUP):
16+
utc = naive.tz_localize("UTC")
17+
utc.tz_convert("America/New_York")
18+
naive.tz_localize("America/New_York", ambiguous="NaT", nonexistent="NaT")
19+
20+
start = time.perf_counter()
21+
for _ in range(ITERATIONS):
22+
utc = naive.tz_localize("UTC")
23+
utc.tz_convert("America/New_York")
24+
naive.tz_localize("America/New_York", ambiguous="NaT", nonexistent="NaT")
25+
total = (time.perf_counter() - start) * 1000
26+
27+
print(json.dumps({
28+
"function": "tz_localize_convert",
29+
"mean_ms": total / ITERATIONS,
30+
"iterations": ITERATIONS,
31+
"total_ms": total,
32+
}))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Benchmark: Series.value_counts(bins=N) — bin 100k values and count occurrences.
3+
Outputs JSON: {"function": "value_counts_binned", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 50
13+
14+
data = [(i % 1000) * 0.1 for i in range(SIZE)]
15+
s = pd.Series(data)
16+
17+
for _ in range(WARMUP):
18+
s.value_counts(bins=10)
19+
s.value_counts(bins=50)
20+
21+
start = time.perf_counter()
22+
for _ in range(ITERATIONS):
23+
s.value_counts(bins=10)
24+
s.value_counts(bins=50)
25+
total = (time.perf_counter() - start) * 1000
26+
27+
print(json.dumps({
28+
"function": "value_counts_binned",
29+
"mean_ms": total / ITERATIONS,
30+
"iterations": ITERATIONS,
31+
"total_ms": total,
32+
}))
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Benchmark: alignDataFrame — align two 10k-row DataFrames on inner/outer join.
3+
* Outputs JSON: {"function": "align_dataframe", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, Index, alignDataFrame } from "../../src/index.ts";
6+
7+
const SIZE = 10_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
const idxA = Array.from({ length: SIZE }, (_, i) => i * 2);
12+
const idxB = Array.from({ length: SIZE }, (_, i) => i * 3);
13+
14+
const dfA = new DataFrame(
15+
{
16+
x: Array.from({ length: SIZE }, (_, i) => i * 1.0),
17+
y: Array.from({ length: SIZE }, (_, i) => i * 2.0),
18+
z: Array.from({ length: SIZE }, (_, i) => i * 3.0),
19+
},
20+
{ index: new Index(idxA) },
21+
);
22+
23+
const dfB = new DataFrame(
24+
{
25+
y: Array.from({ length: SIZE }, (_, i) => i * 10.0),
26+
z: Array.from({ length: SIZE }, (_, i) => i * 20.0),
27+
w: Array.from({ length: SIZE }, (_, i) => i * 30.0),
28+
},
29+
{ index: new Index(idxB) },
30+
);
31+
32+
for (let i = 0; i < WARMUP; i++) {
33+
alignDataFrame(dfA, dfB, { join: "inner" });
34+
alignDataFrame(dfA, dfB, { join: "outer" });
35+
alignDataFrame(dfA, dfB, { join: "left" });
36+
}
37+
38+
const start = performance.now();
39+
for (let i = 0; i < ITERATIONS; i++) {
40+
alignDataFrame(dfA, dfB, { join: "inner" });
41+
alignDataFrame(dfA, dfB, { join: "outer" });
42+
alignDataFrame(dfA, dfB, { join: "left" });
43+
}
44+
const total = performance.now() - start;
45+
46+
console.log(
47+
JSON.stringify({
48+
function: "align_dataframe",
49+
mean_ms: total / ITERATIONS,
50+
iterations: ITERATIONS,
51+
total_ms: total,
52+
}),
53+
);

0 commit comments

Comments
 (0)