Skip to content

Commit 0258e6f

Browse files
Iteration 159: 5 new benchmark pairs (513 total, +5 vs best 508)
Added benchmarks for: - series_sign: seriesSign element-wise sign function (numpy.sign equivalent) - groupby_groups_props: DataFrameGroupBy .groups/.groupKeys/.ngroups properties - merge_sort: merge with sort=true option (pd.merge sort=True equivalent) - series_groupby_groups: SeriesGroupBy .groups/.groupKeys/.ngroups properties - pipe_fn: pipe functional composition operator (Series.pipe equivalent) Run: https://github.com/githubnext/tsessebe/actions/runs/24577736975 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7d019b0 commit 0258e6f

10 files changed

Lines changed: 377 additions & 0 deletions
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Benchmark: DataFrameGroupBy .groups / .ngroups properties on 100k-row DataFrame."""
2+
import json
3+
import time
4+
import numpy as np
5+
import pandas as pd
6+
7+
SIZE = 100_000
8+
WARMUP = 5
9+
ITERATIONS = 50
10+
11+
depts = ["eng", "hr", "sales", "finance", "ops", "legal", "mkt", "it", "rd", "ops2"]
12+
df = pd.DataFrame({
13+
"dept": [depts[i % len(depts)] for i in range(SIZE)],
14+
"salary": [50_000 + (i % 100) * 1000 for i in range(SIZE)],
15+
"score": [(i % 100) * 0.01 for i in range(SIZE)],
16+
})
17+
18+
gb = df.groupby("dept")
19+
20+
for _ in range(WARMUP):
21+
_g = gb.groups
22+
_k = list(gb.groups.keys())
23+
_n = gb.ngroups
24+
25+
times = []
26+
for _ in range(ITERATIONS):
27+
start = time.perf_counter()
28+
_g = gb.groups
29+
_k = list(gb.groups.keys())
30+
_n = gb.ngroups
31+
times.append((time.perf_counter() - start) * 1000)
32+
33+
total_ms = sum(times)
34+
mean_ms = total_ms / ITERATIONS
35+
36+
print(json.dumps({"function": "groupby_groups_props", "mean_ms": mean_ms, "iterations": ITERATIONS, "total_ms": total_ms}))
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Benchmark: merge with sort=True — sort result by join-key on 50k-row DataFrames."""
2+
import json
3+
import time
4+
import numpy as np
5+
import pandas as pd
6+
7+
ROWS = 50_000
8+
WARMUP = 3
9+
ITERATIONS = 20
10+
11+
left = pd.DataFrame({
12+
"id": np.arange(ROWS) % (ROWS // 2),
13+
"val_l": np.arange(ROWS) * 1.5,
14+
})
15+
16+
right = pd.DataFrame({
17+
"id": np.arange(ROWS // 2),
18+
"val_r": np.arange(ROWS // 2) * 2.0,
19+
})
20+
21+
for _ in range(WARMUP):
22+
pd.merge(left, right, on="id", how="inner", sort=True)
23+
24+
times = []
25+
for _ in range(ITERATIONS):
26+
start = time.perf_counter()
27+
pd.merge(left, right, on="id", how="inner", sort=True)
28+
times.append((time.perf_counter() - start) * 1000)
29+
30+
total_ms = sum(times)
31+
mean_ms = total_ms / ITERATIONS
32+
33+
print(json.dumps({"function": "merge_sort", "mean_ms": mean_ms, "iterations": ITERATIONS, "total_ms": total_ms}))

benchmarks/pandas/bench_pipe_fn.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Benchmark: pipe — functional pipeline composition via pandas Series.pipe on 100k-element Series."""
2+
import json
3+
import time
4+
import numpy as np
5+
import pandas as pd
6+
7+
SIZE = 100_000
8+
WARMUP = 5
9+
ITERATIONS = 50
10+
11+
s = pd.Series((np.arange(SIZE) % 200) - 100.0)
12+
df = pd.DataFrame({
13+
"a": (np.arange(SIZE) % 100) - 50.0,
14+
"b": np.sin(np.arange(SIZE) * 0.01) * 100,
15+
})
16+
17+
def double(x: pd.Series) -> pd.Series:
18+
return x * 2
19+
20+
def add_hundred(x: pd.Series) -> pd.Series:
21+
return x + 100
22+
23+
def abs_series(x: pd.Series) -> pd.Series:
24+
return x.abs()
25+
26+
for _ in range(WARMUP):
27+
s.pipe(abs_series).pipe(double).pipe(add_hundred)
28+
29+
times = []
30+
for _ in range(ITERATIONS):
31+
start = time.perf_counter()
32+
s.pipe(abs_series).pipe(double).pipe(add_hundred)
33+
times.append((time.perf_counter() - start) * 1000)
34+
35+
total_ms = sum(times)
36+
mean_ms = total_ms / ITERATIONS
37+
38+
print(json.dumps({"function": "pipe_fn", "mean_ms": mean_ms, "iterations": ITERATIONS, "total_ms": total_ms}))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Benchmark: SeriesGroupBy .groups / .ngroups properties on 100k-element Series."""
2+
import json
3+
import time
4+
import numpy as np
5+
import pandas as pd
6+
7+
SIZE = 100_000
8+
WARMUP = 5
9+
ITERATIONS = 50
10+
11+
categories = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
12+
data = np.arange(SIZE) * 0.1
13+
by = [categories[i % len(categories)] for i in range(SIZE)]
14+
15+
s = pd.Series(data)
16+
gb = s.groupby(by)
17+
18+
for _ in range(WARMUP):
19+
_g = gb.groups
20+
_k = list(gb.groups.keys())
21+
_n = gb.ngroups
22+
23+
times = []
24+
for _ in range(ITERATIONS):
25+
start = time.perf_counter()
26+
_g = gb.groups
27+
_k = list(gb.groups.keys())
28+
_n = gb.ngroups
29+
times.append((time.perf_counter() - start) * 1000)
30+
31+
total_ms = sum(times)
32+
mean_ms = total_ms / ITERATIONS
33+
34+
print(json.dumps({"function": "series_groupby_groups", "mean_ms": mean_ms, "iterations": ITERATIONS, "total_ms": total_ms}))
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Benchmark: seriesSign — element-wise sign via numpy.sign on 100k-element Series."""
2+
import json
3+
import time
4+
import numpy as np
5+
import pandas as pd
6+
7+
SIZE = 100_000
8+
WARMUP = 5
9+
ITERATIONS = 50
10+
11+
data = np.sin(np.arange(SIZE) * 0.01) * 1000
12+
s = pd.Series(data)
13+
14+
for _ in range(WARMUP):
15+
np.sign(s)
16+
17+
times = []
18+
for _ in range(ITERATIONS):
19+
start = time.perf_counter()
20+
np.sign(s)
21+
times.append((time.perf_counter() - start) * 1000)
22+
23+
total_ms = sum(times)
24+
mean_ms = total_ms / ITERATIONS
25+
26+
print(json.dumps({"function": "series_sign", "mean_ms": mean_ms, "iterations": ITERATIONS, "total_ms": total_ms}))
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Benchmark: DataFrameGroupBy .groups / .groupKeys / .ngroups properties on 100k rows.
3+
* Outputs JSON: {"function": "groupby_groups_props", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, DataFrameGroupBy } from "../../src/index.ts";
6+
7+
const SIZE = 100_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 50;
10+
11+
const depts = ["eng", "hr", "sales", "finance", "ops", "legal", "mkt", "it", "rd", "ops2"];
12+
const df = DataFrame.fromColumns({
13+
dept: Array.from({ length: SIZE }, (_, i) => depts[i % depts.length]),
14+
salary: Array.from({ length: SIZE }, (_, i) => 50_000 + (i % 100) * 1000),
15+
score: Array.from({ length: SIZE }, (_, i) => (i % 100) * 0.01),
16+
});
17+
18+
const gb = new DataFrameGroupBy(df, ["dept"]);
19+
20+
for (let i = 0; i < WARMUP; i++) {
21+
const _g = gb.groups;
22+
const _k = gb.groupKeys;
23+
const _n = gb.ngroups;
24+
}
25+
26+
const times: number[] = [];
27+
for (let i = 0; i < ITERATIONS; i++) {
28+
const start = performance.now();
29+
const _g = gb.groups;
30+
const _k = gb.groupKeys;
31+
const _n = gb.ngroups;
32+
times.push(performance.now() - start);
33+
}
34+
35+
const totalMs = times.reduce((a, b) => a + b, 0);
36+
const meanMs = totalMs / ITERATIONS;
37+
38+
console.log(
39+
JSON.stringify({
40+
function: "groupby_groups_props",
41+
mean_ms: meanMs,
42+
iterations: ITERATIONS,
43+
total_ms: totalMs,
44+
}),
45+
);

benchmarks/tsb/bench_merge_sort.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Benchmark: merge with sort=true — sort result by join-key values on 50k-row DataFrames.
3+
* Outputs JSON: {"function": "merge_sort", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, merge } from "../../src/index.ts";
6+
7+
const ROWS = 50_000;
8+
const WARMUP = 3;
9+
const ITERATIONS = 20;
10+
11+
const left = DataFrame.fromColumns({
12+
id: Array.from({ length: ROWS }, (_, i) => i % (ROWS / 2)),
13+
val_l: Array.from({ length: ROWS }, (_, i) => i * 1.5),
14+
});
15+
16+
const right = DataFrame.fromColumns({
17+
id: Array.from({ length: ROWS / 2 }, (_, i) => i),
18+
val_r: Array.from({ length: ROWS / 2 }, (_, i) => i * 2.0),
19+
});
20+
21+
for (let i = 0; i < WARMUP; i++) {
22+
merge(left, right, { on: "id", how: "inner", sort: true });
23+
}
24+
25+
const times: number[] = [];
26+
for (let i = 0; i < ITERATIONS; i++) {
27+
const start = performance.now();
28+
merge(left, right, { on: "id", how: "inner", sort: true });
29+
times.push(performance.now() - start);
30+
}
31+
32+
const totalMs = times.reduce((a, b) => a + b, 0);
33+
const meanMs = totalMs / ITERATIONS;
34+
35+
console.log(
36+
JSON.stringify({
37+
function: "merge_sort",
38+
mean_ms: meanMs,
39+
iterations: ITERATIONS,
40+
total_ms: totalMs,
41+
}),
42+
);

benchmarks/tsb/bench_pipe_fn.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Benchmark: pipe — functional pipeline composition operator on 100k-element Series and DataFrame.
3+
* Outputs JSON: {"function": "pipe_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Series, DataFrame, pipe, seriesAbs, seriesMul, seriesAdd } from "../../src/index.ts";
6+
import type { Scalar } from "../../src/types.ts";
7+
8+
const SIZE = 100_000;
9+
const WARMUP = 5;
10+
const ITERATIONS = 50;
11+
12+
const s = new Series({ data: Array.from({ length: SIZE }, (_, i) => (i % 200) - 100.0) });
13+
const df = DataFrame.fromColumns({
14+
a: Array.from({ length: SIZE }, (_, i) => (i % 100) - 50.0),
15+
b: Array.from({ length: SIZE }, (_, i) => Math.sin(i * 0.01) * 100),
16+
});
17+
18+
const double = (x: Series<Scalar>) => seriesMul(x, 2);
19+
const addHundred = (x: Series<Scalar>) => seriesAdd(x, 100);
20+
const abs = (x: Series<Scalar>) => seriesAbs(x);
21+
22+
for (let i = 0; i < WARMUP; i++) {
23+
pipe(s, abs, double, addHundred);
24+
pipe(42, (x: number) => x * 2, (x: number) => x + 1);
25+
}
26+
27+
const times: number[] = [];
28+
for (let i = 0; i < ITERATIONS; i++) {
29+
const start = performance.now();
30+
pipe(s, abs, double, addHundred);
31+
pipe(42, (x: number) => x * 2, (x: number) => x + 1);
32+
times.push(performance.now() - start);
33+
}
34+
35+
const totalMs = times.reduce((a, b) => a + b, 0);
36+
const meanMs = totalMs / ITERATIONS;
37+
38+
console.log(
39+
JSON.stringify({
40+
function: "pipe_fn",
41+
mean_ms: meanMs,
42+
iterations: ITERATIONS,
43+
total_ms: totalMs,
44+
}),
45+
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Benchmark: SeriesGroupBy .groups / .groupKeys / .ngroups properties on 100k-element Series.
3+
* Outputs JSON: {"function": "series_groupby_groups", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Series, SeriesGroupBy } from "../../src/index.ts";
6+
7+
const SIZE = 100_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 50;
10+
11+
const categories = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
12+
const data = Array.from({ length: SIZE }, (_, i) => i * 0.1);
13+
const by = Array.from({ length: SIZE }, (_, i) => categories[i % categories.length]);
14+
15+
const s = new Series({ data });
16+
const gb = new SeriesGroupBy(s, by);
17+
18+
for (let i = 0; i < WARMUP; i++) {
19+
const _g = gb.groups;
20+
const _k = gb.groupKeys;
21+
const _n = gb.ngroups;
22+
}
23+
24+
const times: number[] = [];
25+
for (let i = 0; i < ITERATIONS; i++) {
26+
const start = performance.now();
27+
const _g = gb.groups;
28+
const _k = gb.groupKeys;
29+
const _n = gb.ngroups;
30+
times.push(performance.now() - start);
31+
}
32+
33+
const totalMs = times.reduce((a, b) => a + b, 0);
34+
const meanMs = totalMs / ITERATIONS;
35+
36+
console.log(
37+
JSON.stringify({
38+
function: "series_groupby_groups",
39+
mean_ms: meanMs,
40+
iterations: ITERATIONS,
41+
total_ms: totalMs,
42+
}),
43+
);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Benchmark: seriesSign — element-wise sign on 100k-element Series.
3+
* Outputs JSON: {"function": "series_sign", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Series, seriesSign } from "../../src/index.ts";
6+
7+
const SIZE = 100_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 50;
10+
11+
const data = Array.from({ length: SIZE }, (_, i) => Math.sin(i * 0.01) * 1000);
12+
const s = new Series({ data });
13+
14+
for (let i = 0; i < WARMUP; i++) {
15+
seriesSign(s);
16+
}
17+
18+
const times: number[] = [];
19+
for (let i = 0; i < ITERATIONS; i++) {
20+
const start = performance.now();
21+
seriesSign(s);
22+
times.push(performance.now() - start);
23+
}
24+
25+
const totalMs = times.reduce((a, b) => a + b, 0);
26+
const meanMs = totalMs / ITERATIONS;
27+
28+
console.log(
29+
JSON.stringify({
30+
function: "series_sign",
31+
mean_ms: meanMs,
32+
iterations: ITERATIONS,
33+
total_ms: totalMs,
34+
}),
35+
);

0 commit comments

Comments
 (0)