Skip to content

Commit 1cab883

Browse files
Iteration 173: 25 new benchmark pairs (559 total, +20 via merge + 5 new)
Merged 20 benchmark pairs from non-canonical branch (iterations 167-170): cummax_cummin_str, cumops_skipna, dataframe_cov_options, dataframe_cumops_axis1, dataframe_rolling_apply_fn, dropna_thresh_subset, histogram_bin_edges, interpolate_zero_nearest, json_normalize_meta, nan_sum_mean_std, nan_var_min_max, nancumops_extra, pct_change_fill_method, pivot_table_aggfunc_variants, pivot_table_fill_value, read_json_all_orients, reindex_fill_methods, sample_weights, series_cumops_nan, wide_to_long_sep_suffix. Added 5 new benchmark pairs: - interpolate_methods: all 5 methods (linear/ffill/bfill/nearest/zero) - explode_dataframe: explodeDataFrame list-column expansion - nlargest_dataframe: nlargestDataFrame/nsmallestDataFrame top-N rows - select_dtypes_options: selectDtypes with include/exclude variants - get_dummies_drop_first: getDummies/dataFrameGetDummies with drop_first + prefix Metric: 559 (previous best: 539, delta: +20) Run: https://github.com/githubnext/tsessebe/actions/runs/24594692249 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7178c40 commit 1cab883

10 files changed

Lines changed: 352 additions & 0 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Benchmark: DataFrame.explode() — explode list-column into rows."""
2+
import json, time
3+
import pandas as pd
4+
5+
ROWS = 10_000
6+
WARMUP = 5
7+
ITERATIONS = 30
8+
9+
vals = [[i, i + 1, i + 2] for i in range(ROWS)]
10+
labels = [f"cat_{i % 100}" for i in range(ROWS)]
11+
df = pd.DataFrame({"vals": vals, "labels": labels})
12+
13+
for _ in range(WARMUP):
14+
df.explode("vals")
15+
16+
times = []
17+
for _ in range(ITERATIONS):
18+
t0 = time.perf_counter()
19+
df.explode("vals")
20+
times.append((time.perf_counter() - t0) * 1000)
21+
22+
total_ms = sum(times)
23+
print(json.dumps({"function": "explode_dataframe", "mean_ms": round(total_ms / ITERATIONS, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Benchmark: pd.get_dummies with drop_first and prefix options."""
2+
import json, time
3+
import pandas as pd
4+
import numpy as np
5+
6+
ROWS = 50_000
7+
WARMUP = 5
8+
ITERATIONS = 30
9+
10+
cat_data = [f"cat_{i % 10}" for i in range(ROWS)]
11+
s = pd.Categorical(cat_data)
12+
df = pd.DataFrame({
13+
"category": cat_data,
14+
"value": np.arange(ROWS, dtype=np.float64) * 0.1,
15+
})
16+
17+
for _ in range(WARMUP):
18+
pd.get_dummies(s, drop_first=True)
19+
pd.get_dummies(s, prefix="grp", prefix_sep="_")
20+
pd.get_dummies(df, columns=["category"], drop_first=True)
21+
22+
times = []
23+
for _ in range(ITERATIONS):
24+
t0 = time.perf_counter()
25+
pd.get_dummies(s, drop_first=True)
26+
pd.get_dummies(s, prefix="grp", prefix_sep="_")
27+
pd.get_dummies(df, columns=["category"], drop_first=True)
28+
times.append((time.perf_counter() - t0) * 1000)
29+
30+
total_ms = sum(times)
31+
print(json.dumps({"function": "get_dummies_drop_first", "mean_ms": round(total_ms / ITERATIONS, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Benchmark: interpolateSeries with linear, ffill, bfill, nearest, zero methods."""
2+
import json, time
3+
import pandas as pd
4+
import numpy as np
5+
6+
SIZE = 50_000
7+
WARMUP = 5
8+
ITERATIONS = 30
9+
10+
data = [float(i) * 0.1 if i % 5 != 0 else None for i in range(SIZE)]
11+
s = pd.Series(data, dtype=float)
12+
13+
for _ in range(WARMUP):
14+
s.interpolate(method="linear")
15+
s.ffill()
16+
s.bfill()
17+
s.interpolate(method="nearest")
18+
s.interpolate(method="zero")
19+
20+
times = []
21+
for _ in range(ITERATIONS):
22+
t0 = time.perf_counter()
23+
s.interpolate(method="linear")
24+
s.ffill()
25+
s.bfill()
26+
s.interpolate(method="nearest")
27+
s.interpolate(method="zero")
28+
times.append((time.perf_counter() - t0) * 1000)
29+
30+
total_ms = sum(times)
31+
print(json.dumps({"function": "interpolate_methods", "mean_ms": round(total_ms / ITERATIONS, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Benchmark: DataFrame.nlargest / nsmallest — top-N rows by column."""
2+
import json, time
3+
import pandas as pd
4+
import numpy as np
5+
6+
ROWS = 100_000
7+
N = 100
8+
WARMUP = 5
9+
ITERATIONS = 30
10+
11+
rng = np.random.default_rng(42)
12+
df = pd.DataFrame({
13+
"a": rng.random(ROWS) * 1000,
14+
"b": rng.random(ROWS) * 500,
15+
"c": rng.random(ROWS) * 100,
16+
})
17+
18+
for _ in range(WARMUP):
19+
df.nlargest(N, "a")
20+
df.nsmallest(N, "b")
21+
22+
times = []
23+
for _ in range(ITERATIONS):
24+
t0 = time.perf_counter()
25+
df.nlargest(N, "a")
26+
df.nsmallest(N, "b")
27+
times.append((time.perf_counter() - t0) * 1000)
28+
29+
total_ms = sum(times)
30+
print(json.dumps({"function": "nlargest_dataframe", "mean_ms": round(total_ms / ITERATIONS, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Benchmark: DataFrame.select_dtypes() — filter columns by dtype (include/exclude)."""
2+
import json, time
3+
import pandas as pd
4+
import numpy as np
5+
6+
ROWS = 50_000
7+
WARMUP = 5
8+
ITERATIONS = 30
9+
10+
rng = np.random.default_rng(42)
11+
df = pd.DataFrame({
12+
"intCol": np.arange(ROWS, dtype=np.int32),
13+
"floatCol": np.arange(ROWS, dtype=np.float64) * 1.5,
14+
"boolCol": np.arange(ROWS) % 2 == 0,
15+
"strCol": [f"s_{i % 100}" for i in range(ROWS)],
16+
})
17+
18+
for _ in range(WARMUP):
19+
df.select_dtypes(include="number")
20+
df.select_dtypes(exclude="number")
21+
df.select_dtypes(include=["int", "float"])
22+
23+
times = []
24+
for _ in range(ITERATIONS):
25+
t0 = time.perf_counter()
26+
df.select_dtypes(include="number")
27+
df.select_dtypes(exclude="number")
28+
df.select_dtypes(include=["int", "float"])
29+
times.append((time.perf_counter() - t0) * 1000)
30+
31+
total_ms = sum(times)
32+
print(json.dumps({"function": "select_dtypes_options", "mean_ms": round(total_ms / ITERATIONS, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Benchmark: explodeDataFrame — explode list-column into rows.
3+
* Outputs JSON: {"function": "explode_dataframe", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, Series, explodeDataFrame } from "../../src/index.ts";
6+
7+
const ROWS = 10_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
// Each row has a list of 3-5 elements in column "vals"
12+
const vals = Array.from({ length: ROWS }, (_, i) => [i, i + 1, i + 2]);
13+
const labels = Array.from({ length: ROWS }, (_, i) => `cat_${i % 100}`);
14+
const df = DataFrame.fromColumns({ vals, labels });
15+
16+
for (let i = 0; i < WARMUP; i++) {
17+
explodeDataFrame(df, "vals");
18+
}
19+
20+
const times: number[] = [];
21+
for (let i = 0; i < ITERATIONS; i++) {
22+
const start = performance.now();
23+
explodeDataFrame(df, "vals");
24+
times.push(performance.now() - start);
25+
}
26+
27+
const totalMs = times.reduce((a, b) => a + b, 0);
28+
const meanMs = totalMs / ITERATIONS;
29+
console.log(
30+
JSON.stringify({
31+
function: "explode_dataframe",
32+
mean_ms: Math.round(meanMs * 1000) / 1000,
33+
iterations: ITERATIONS,
34+
total_ms: Math.round(totalMs * 1000) / 1000,
35+
}),
36+
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Benchmark: getDummies / dataFrameGetDummies with drop_first and prefix options.
3+
* Outputs JSON: {"function": "get_dummies_drop_first", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Series, DataFrame, getDummies, dataFrameGetDummies } from "../../src/index.ts";
6+
7+
const ROWS = 50_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
// Categorical series with 10 distinct values
12+
const catData = Array.from({ length: ROWS }, (_, i) => `cat_${i % 10}`);
13+
const s = new Series({ data: catData });
14+
const df = DataFrame.fromColumns({
15+
category: catData,
16+
value: Float64Array.from({ length: ROWS }, (_, i) => i * 0.1),
17+
});
18+
19+
for (let i = 0; i < WARMUP; i++) {
20+
getDummies(s, { dropFirst: true });
21+
getDummies(s, { prefix: "grp", prefixSep: "_" });
22+
dataFrameGetDummies(df, { columns: ["category"], dropFirst: true });
23+
}
24+
25+
const times: number[] = [];
26+
for (let i = 0; i < ITERATIONS; i++) {
27+
const start = performance.now();
28+
getDummies(s, { dropFirst: true });
29+
getDummies(s, { prefix: "grp", prefixSep: "_" });
30+
dataFrameGetDummies(df, { columns: ["category"], dropFirst: true });
31+
times.push(performance.now() - start);
32+
}
33+
34+
const totalMs = times.reduce((a, b) => a + b, 0);
35+
const meanMs = totalMs / ITERATIONS;
36+
console.log(
37+
JSON.stringify({
38+
function: "get_dummies_drop_first",
39+
mean_ms: Math.round(meanMs * 1000) / 1000,
40+
iterations: ITERATIONS,
41+
total_ms: Math.round(totalMs * 1000) / 1000,
42+
}),
43+
);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Benchmark: interpolateSeries with linear, ffill, bfill, nearest, zero methods.
3+
* Outputs JSON: {"function": "interpolate_methods", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Series, interpolateSeries } from "../../src/index.ts";
6+
7+
const SIZE = 50_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
// Build a series with ~20% NaN scattered
12+
const data: (number | null)[] = Array.from({ length: SIZE }, (_, i) =>
13+
i % 5 === 0 ? null : i * 0.1,
14+
);
15+
const s = new Series({ data });
16+
17+
for (let i = 0; i < WARMUP; i++) {
18+
interpolateSeries(s, { method: "linear" });
19+
interpolateSeries(s, { method: "ffill" });
20+
interpolateSeries(s, { method: "bfill" });
21+
interpolateSeries(s, { method: "nearest" });
22+
interpolateSeries(s, { method: "zero" });
23+
}
24+
25+
const times: number[] = [];
26+
for (let i = 0; i < ITERATIONS; i++) {
27+
const start = performance.now();
28+
interpolateSeries(s, { method: "linear" });
29+
interpolateSeries(s, { method: "ffill" });
30+
interpolateSeries(s, { method: "bfill" });
31+
interpolateSeries(s, { method: "nearest" });
32+
interpolateSeries(s, { method: "zero" });
33+
times.push(performance.now() - start);
34+
}
35+
36+
const totalMs = times.reduce((a, b) => a + b, 0);
37+
const meanMs = totalMs / ITERATIONS;
38+
console.log(
39+
JSON.stringify({
40+
function: "interpolate_methods",
41+
mean_ms: Math.round(meanMs * 1000) / 1000,
42+
iterations: ITERATIONS,
43+
total_ms: Math.round(totalMs * 1000) / 1000,
44+
}),
45+
);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Benchmark: nlargestDataFrame / nsmallestDataFrame — top-N rows by multiple columns.
3+
* Outputs JSON: {"function": "nlargest_dataframe", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, Series, nlargestDataFrame, nsmallestDataFrame } from "../../src/index.ts";
6+
7+
const ROWS = 100_000;
8+
const N = 100;
9+
const WARMUP = 5;
10+
const ITERATIONS = 30;
11+
12+
const a = new Series({ data: Float64Array.from({ length: ROWS }, () => Math.random() * 1000) });
13+
const b = new Series({ data: Float64Array.from({ length: ROWS }, () => Math.random() * 500) });
14+
const c = new Series({ data: Float64Array.from({ length: ROWS }, () => Math.random() * 100) });
15+
const df = DataFrame.fromColumns({ a, b, c });
16+
17+
for (let i = 0; i < WARMUP; i++) {
18+
nlargestDataFrame(df, N, { columns: ["a"] });
19+
nsmallestDataFrame(df, N, { columns: ["b"] });
20+
}
21+
22+
const times: number[] = [];
23+
for (let i = 0; i < ITERATIONS; i++) {
24+
const start = performance.now();
25+
nlargestDataFrame(df, N, { columns: ["a"] });
26+
nsmallestDataFrame(df, N, { columns: ["b"] });
27+
times.push(performance.now() - start);
28+
}
29+
30+
const totalMs = times.reduce((a, b) => a + b, 0);
31+
const meanMs = totalMs / ITERATIONS;
32+
console.log(
33+
JSON.stringify({
34+
function: "nlargest_dataframe",
35+
mean_ms: Math.round(meanMs * 1000) / 1000,
36+
iterations: ITERATIONS,
37+
total_ms: Math.round(totalMs * 1000) / 1000,
38+
}),
39+
);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Benchmark: selectDtypes — filter DataFrame columns by dtype (include/exclude).
3+
* Outputs JSON: {"function": "select_dtypes_options", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, Series, selectDtypes } from "../../src/index.ts";
6+
7+
const ROWS = 50_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
// Build a mixed-dtype DataFrame
12+
const intCol = new Series({ data: Int32Array.from({ length: ROWS }, (_, i) => i) });
13+
const floatCol = new Series({ data: Float64Array.from({ length: ROWS }, (_, i) => i * 1.5) });
14+
const boolCol = new Series({ data: Array.from({ length: ROWS }, (_, i) => i % 2 === 0) });
15+
const strCol = new Series({ data: Array.from({ length: ROWS }, (_, i) => `s_${i % 100}`) });
16+
const df = DataFrame.fromColumns({ intCol, floatCol, boolCol, strCol });
17+
18+
for (let i = 0; i < WARMUP; i++) {
19+
selectDtypes(df, { include: "number" });
20+
selectDtypes(df, { exclude: "number" });
21+
selectDtypes(df, { include: ["integer", "float"] });
22+
}
23+
24+
const times: number[] = [];
25+
for (let i = 0; i < ITERATIONS; i++) {
26+
const start = performance.now();
27+
selectDtypes(df, { include: "number" });
28+
selectDtypes(df, { exclude: "number" });
29+
selectDtypes(df, { include: ["integer", "float"] });
30+
times.push(performance.now() - start);
31+
}
32+
33+
const totalMs = times.reduce((a, b) => a + b, 0);
34+
const meanMs = totalMs / ITERATIONS;
35+
console.log(
36+
JSON.stringify({
37+
function: "select_dtypes_options",
38+
mean_ms: Math.round(meanMs * 1000) / 1000,
39+
iterations: ITERATIONS,
40+
total_ms: Math.round(totalMs * 1000) / 1000,
41+
}),
42+
);

0 commit comments

Comments
 (0)