Skip to content

Commit 9198f7a

Browse files
[Autoloop: perf-comparison] Iteration 377: add 6 benchmark pairs (iterrows, items, fromRecords, groupby many groups, concat many frames, str replace regex)
Run: https://github.com/githubnext/tsb/actions/runs/28299081916 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a7a548e commit 9198f7a

12 files changed

Lines changed: 446 additions & 0 deletions
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Benchmark: pd.concat() with 20 DataFrames — many-frame concatenation on 100k total rows."""
2+
import json
3+
import time
4+
import pandas as pd
5+
6+
N_FRAMES = 20
7+
ROWS_EACH = 5_000
8+
WARMUP = 5
9+
ITERATIONS = 20
10+
11+
frames = [
12+
pd.DataFrame({
13+
"a": [float(f * ROWS_EACH + i) for i in range(ROWS_EACH)],
14+
"b": [(f * ROWS_EACH + i) % 100 for i in range(ROWS_EACH)],
15+
"c": [f"cat_{i % 20}" for i in range(ROWS_EACH)],
16+
})
17+
for f in range(N_FRAMES)
18+
]
19+
20+
for _ in range(WARMUP):
21+
pd.concat(frames)
22+
23+
times = []
24+
for _ in range(ITERATIONS):
25+
t0 = time.perf_counter()
26+
pd.concat(frames)
27+
times.append((time.perf_counter() - t0) * 1000)
28+
29+
total = sum(times)
30+
print(json.dumps({
31+
"function": "concat_many_frames",
32+
"mean_ms": total / ITERATIONS,
33+
"iterations": ITERATIONS,
34+
"total_ms": total,
35+
}))
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Benchmark: DataFrame.from_records() — construct a DataFrame from a list of dicts."""
2+
import json
3+
import time
4+
import pandas as pd
5+
6+
ROWS = 20_000
7+
WARMUP = 5
8+
ITERATIONS = 20
9+
10+
records = [
11+
{"id": i, "value": i * 1.5, "category": f"cat_{i % 50}", "score": None if i % 2 == 0 else i * 0.1, "rank": i % 100}
12+
for i in range(ROWS)
13+
]
14+
15+
for _ in range(WARMUP):
16+
pd.DataFrame.from_records(records)
17+
18+
times = []
19+
for _ in range(ITERATIONS):
20+
t0 = time.perf_counter()
21+
pd.DataFrame.from_records(records)
22+
times.append((time.perf_counter() - t0) * 1000)
23+
24+
total = sum(times)
25+
print(json.dumps({
26+
"function": "dataframe_from_records",
27+
"mean_ms": total / ITERATIONS,
28+
"iterations": ITERATIONS,
29+
"total_ms": total,
30+
}))
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Benchmark: DataFrame.items() / iteritems() — iterate over (columnName, Series) pairs."""
2+
import json
3+
import time
4+
import pandas as pd
5+
6+
ROWS = 50_000
7+
WARMUP = 5
8+
ITERATIONS = 50
9+
10+
df = pd.DataFrame({
11+
"a": [float(i) for i in range(ROWS)],
12+
"b": [i % 500 for i in range(ROWS)],
13+
"c": [f"cat_{i % 50}" for i in range(ROWS)],
14+
"d": [i * 0.25 for i in range(ROWS)],
15+
"e": [None if i % 2 == 0 else i * 1.5 for i in range(ROWS)],
16+
"f": [i * 3 for i in range(ROWS)],
17+
})
18+
19+
for _ in range(WARMUP):
20+
n = 0
21+
for _name, _col in df.items():
22+
n += 1
23+
for _name, _col in df.iteritems() if hasattr(df, "iteritems") else df.items():
24+
n += 1
25+
26+
times = []
27+
for _ in range(ITERATIONS):
28+
t0 = time.perf_counter()
29+
n = 0
30+
for _name, _col in df.items():
31+
n += 1
32+
for _name, _col in df.iteritems() if hasattr(df, "iteritems") else df.items():
33+
n += 1
34+
times.append((time.perf_counter() - t0) * 1000)
35+
36+
total = sum(times)
37+
print(json.dumps({
38+
"function": "dataframe_items",
39+
"mean_ms": total / ITERATIONS,
40+
"iterations": ITERATIONS,
41+
"total_ms": total,
42+
}))
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Benchmark: DataFrame.iterrows() — iterate over (label, Series) pairs on a 3k-row DataFrame."""
2+
import json
3+
import time
4+
import pandas as pd
5+
6+
ROWS = 3_000
7+
WARMUP = 5
8+
ITERATIONS = 30
9+
10+
df = pd.DataFrame({
11+
"a": [float(i) for i in range(ROWS)],
12+
"b": [i % 100 for i in range(ROWS)],
13+
"c": [f"cat_{i % 20}" for i in range(ROWS)],
14+
"d": [None if i % 2 == 0 else i * 0.5 for i in range(ROWS)],
15+
"e": [i * 2 for i in range(ROWS)],
16+
})
17+
18+
for _ in range(WARMUP):
19+
n = 0
20+
for _label, _row in df.iterrows():
21+
n += 1
22+
23+
times = []
24+
for _ in range(ITERATIONS):
25+
t0 = time.perf_counter()
26+
n = 0
27+
for _label, _row in df.iterrows():
28+
n += 1
29+
times.append((time.perf_counter() - t0) * 1000)
30+
31+
total = sum(times)
32+
print(json.dumps({
33+
"function": "dataframe_iterrows",
34+
"mean_ms": total / ITERATIONS,
35+
"iterations": ITERATIONS,
36+
"total_ms": total,
37+
}))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Benchmark: DataFrame.groupby().sum() with 1000 groups on a 100k-row DataFrame."""
2+
import json
3+
import time
4+
import pandas as pd
5+
6+
ROWS = 100_000
7+
N_GROUPS = 1_000
8+
WARMUP = 3
9+
ITERATIONS = 10
10+
11+
df = pd.DataFrame({
12+
"key": [f"g{i % N_GROUPS}" for i in range(ROWS)],
13+
"val1": [i * 0.5 for i in range(ROWS)],
14+
"val2": [i % 200 for i in range(ROWS)],
15+
})
16+
17+
for _ in range(WARMUP):
18+
df.groupby("key").sum()
19+
20+
times = []
21+
for _ in range(ITERATIONS):
22+
t0 = time.perf_counter()
23+
df.groupby("key").sum()
24+
times.append((time.perf_counter() - t0) * 1000)
25+
26+
total = sum(times)
27+
print(json.dumps({
28+
"function": "groupby_sum_many_groups",
29+
"mean_ms": total / ITERATIONS,
30+
"iterations": ITERATIONS,
31+
"total_ms": total,
32+
}))
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Benchmark: Series.str.replace() with a regex pattern on 50k strings."""
2+
import json
3+
import time
4+
import pandas as pd
5+
6+
ROWS = 50_000
7+
WARMUP = 5
8+
ITERATIONS = 30
9+
10+
data = [f"item_{i % 1000}_val{i % 50}" for i in range(ROWS)]
11+
s = pd.Series(data)
12+
13+
for _ in range(WARMUP):
14+
s.str.replace(r"[0-9]+", "#", regex=True)
15+
16+
times = []
17+
for _ in range(ITERATIONS):
18+
t0 = time.perf_counter()
19+
s.str.replace(r"[0-9]+", "#", regex=True)
20+
times.append((time.perf_counter() - t0) * 1000)
21+
22+
total = sum(times)
23+
print(json.dumps({
24+
"function": "series_str_replace_regex",
25+
"mean_ms": total / ITERATIONS,
26+
"iterations": ITERATIONS,
27+
"total_ms": total,
28+
}))
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Benchmark: concat() with 20 DataFrames — many-frame concatenation on 100k total rows.
3+
* Outputs JSON: {"function": "concat_many_frames", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, concat } from "../../src/index.ts";
6+
7+
const N_FRAMES = 20;
8+
const ROWS_EACH = 5_000;
9+
const WARMUP = 5;
10+
const ITERATIONS = 20;
11+
12+
const frames = Array.from({ length: N_FRAMES }, (_, f) =>
13+
DataFrame.fromColumns({
14+
a: Array.from({ length: ROWS_EACH }, (_, i) => (f * ROWS_EACH + i) * 1.0),
15+
b: Array.from({ length: ROWS_EACH }, (_, i) => (f * ROWS_EACH + i) % 100),
16+
c: Array.from({ length: ROWS_EACH }, (_, i) => `cat_${i % 20}`),
17+
}),
18+
);
19+
20+
for (let i = 0; i < WARMUP; i++) {
21+
concat(frames);
22+
}
23+
24+
const times: number[] = [];
25+
for (let i = 0; i < ITERATIONS; i++) {
26+
const t0 = performance.now();
27+
concat(frames);
28+
times.push(performance.now() - t0);
29+
}
30+
const total = times.reduce((a, b) => a + b, 0);
31+
32+
console.log(
33+
JSON.stringify({
34+
function: "concat_many_frames",
35+
mean_ms: total / ITERATIONS,
36+
iterations: ITERATIONS,
37+
total_ms: total,
38+
}),
39+
);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Benchmark: DataFrame.fromRecords() — construct a DataFrame from an array of record objects.
3+
* Outputs JSON: {"function": "dataframe_from_records", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame } from "../../src/index.ts";
6+
7+
const ROWS = 20_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 20;
10+
11+
const records = Array.from({ length: ROWS }, (_, i) => ({
12+
id: i,
13+
value: i * 1.5,
14+
category: `cat_${i % 50}`,
15+
score: i % 2 === 0 ? null : i * 0.1,
16+
rank: i % 100,
17+
}));
18+
19+
for (let i = 0; i < WARMUP; i++) {
20+
DataFrame.fromRecords(records);
21+
}
22+
23+
const times: number[] = [];
24+
for (let i = 0; i < ITERATIONS; i++) {
25+
const t0 = performance.now();
26+
DataFrame.fromRecords(records);
27+
times.push(performance.now() - t0);
28+
}
29+
const total = times.reduce((a, b) => a + b, 0);
30+
31+
console.log(
32+
JSON.stringify({
33+
function: "dataframe_from_records",
34+
mean_ms: total / ITERATIONS,
35+
iterations: ITERATIONS,
36+
total_ms: total,
37+
}),
38+
);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Benchmark: DataFrame.items() / iteritems() — iterate over (columnName, Series) pairs.
3+
* Outputs JSON: {"function": "dataframe_items", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame } from "../../src/index.ts";
6+
7+
const ROWS = 50_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 50;
10+
11+
const df = DataFrame.fromColumns({
12+
a: Array.from({ length: ROWS }, (_, i) => i * 1.0),
13+
b: Array.from({ length: ROWS }, (_, i) => i % 500),
14+
c: Array.from({ length: ROWS }, (_, i) => `cat_${i % 50}`),
15+
d: Array.from({ length: ROWS }, (_, i) => i * 0.25),
16+
e: Array.from({ length: ROWS }, (_, i) => i % 2 === 0 ? null : i * 1.5),
17+
f: Array.from({ length: ROWS }, (_, i) => i * 3),
18+
});
19+
20+
for (let i = 0; i < WARMUP; i++) {
21+
let n = 0;
22+
for (const [_name, _col] of df.items()) {
23+
n++;
24+
}
25+
for (const [_name, _col] of df.iteritems()) {
26+
n++;
27+
}
28+
}
29+
30+
const times: number[] = [];
31+
for (let i = 0; i < ITERATIONS; i++) {
32+
const t0 = performance.now();
33+
let n = 0;
34+
for (const [_name, _col] of df.items()) {
35+
n++;
36+
}
37+
for (const [_name, _col] of df.iteritems()) {
38+
n++;
39+
}
40+
times.push(performance.now() - t0);
41+
}
42+
const total = times.reduce((a, b) => a + b, 0);
43+
44+
console.log(
45+
JSON.stringify({
46+
function: "dataframe_items",
47+
mean_ms: total / ITERATIONS,
48+
iterations: ITERATIONS,
49+
total_ms: total,
50+
}),
51+
);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Benchmark: DataFrame.iterrows() — iterate over (label, rowSeries) pairs on a 3k-row DataFrame.
3+
* Outputs JSON: {"function": "dataframe_iterrows", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame } from "../../src/index.ts";
6+
7+
const ROWS = 3_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
const df = DataFrame.fromColumns({
12+
a: Array.from({ length: ROWS }, (_, i) => i * 1.0),
13+
b: Array.from({ length: ROWS }, (_, i) => i % 100),
14+
c: Array.from({ length: ROWS }, (_, i) => `cat_${i % 20}`),
15+
d: Array.from({ length: ROWS }, (_, i) => (i % 2 === 0 ? null : i * 0.5)),
16+
e: Array.from({ length: ROWS }, (_, i) => i * 2),
17+
});
18+
19+
for (let i = 0; i < WARMUP; i++) {
20+
let n = 0;
21+
for (const [_label, _row] of df.iterrows()) {
22+
n++;
23+
}
24+
}
25+
26+
const times: number[] = [];
27+
for (let i = 0; i < ITERATIONS; i++) {
28+
const t0 = performance.now();
29+
let n = 0;
30+
for (const [_label, _row] of df.iterrows()) {
31+
n++;
32+
}
33+
times.push(performance.now() - t0);
34+
}
35+
const total = times.reduce((a, b) => a + b, 0);
36+
37+
console.log(
38+
JSON.stringify({
39+
function: "dataframe_iterrows",
40+
mean_ms: total / ITERATIONS,
41+
iterations: ITERATIONS,
42+
total_ms: total,
43+
}),
44+
);

0 commit comments

Comments
 (0)