Skip to content

Commit 8568c4a

Browse files
Iteration 145: Add 9 benchmark pairs (454 total, +9 vs best 445)
Added benchmarks for standalone functional forms not yet covered: - mode_dataframe_fn: modeDataFrame standalone vs pandas df.mode() - where_mask_series_fn: whereSeries/maskSeries standalone vs pandas - where_mask_df_fn: whereDataFrame/maskDataFrame standalone vs pandas - idxmin_max_df: idxminDataFrame/idxmaxDataFrame vs pandas df.idxmin/idxmax - interpolate_fn: interpolateSeries/dataFrameInterpolate standalone vs pandas - explode_fn: explodeSeries/explodeDataFrame standalone vs pandas - fillna_fn: fillnaSeries/fillnaDataFrame standalone vs pandas - dropna_fn: dropnaSeries/dropnaDataFrame standalone vs pandas - diff_applymap_fn: diffSeries/applymap standalone vs pandas Run: https://github.com/githubnext/tsessebe/actions/runs/24551622461 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 5899214 commit 8568c4a

18 files changed

Lines changed: 710 additions & 0 deletions
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Benchmark: pandas Series.diff() + DataFrame.applymap() — diff and element-wise map.
3+
Outputs JSON: {"function": "diff_applymap_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
s = pd.Series([i * 1.0 + np.sin(i * 0.01) for i in range(SIZE)])
15+
16+
df = pd.DataFrame({
17+
"a": [i * 0.1 for i in range(SIZE)],
18+
"b": [i * 0.2 + 1 for i in range(SIZE)],
19+
"c": [i * -0.1 for i in range(SIZE)],
20+
})
21+
22+
for _ in range(WARMUP):
23+
s.diff()
24+
s.diff(2)
25+
df.map(lambda v: v ** 2)
26+
27+
times = []
28+
for _ in range(ITERATIONS):
29+
t0 = time.perf_counter()
30+
s.diff()
31+
s.diff(2)
32+
df.map(lambda v: v ** 2)
33+
times.append((time.perf_counter() - t0) * 1000)
34+
35+
total_ms = sum(times)
36+
mean_ms = total_ms / ITERATIONS
37+
print(json.dumps({"function": "diff_applymap_fn", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Benchmark: pandas Series.dropna() / DataFrame.dropna() — drop missing values.
3+
Outputs JSON: {"function": "dropna_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
series_data = [float("nan") if i % 5 == 0 else i * 1.0 for i in range(SIZE)]
15+
s = pd.Series(series_data)
16+
17+
df = pd.DataFrame({
18+
"a": [float("nan") if i % 5 == 0 else i * 0.1 for i in range(SIZE)],
19+
"b": [float("nan") if i % 7 == 0 else i * 2.0 for i in range(SIZE)],
20+
"c": [float("nan") if i % 3 == 0 else i % 100 for i in range(SIZE)],
21+
})
22+
23+
for _ in range(WARMUP):
24+
s.dropna()
25+
df.dropna()
26+
df.dropna(how="any")
27+
df.dropna(how="all")
28+
29+
times = []
30+
for _ in range(ITERATIONS):
31+
t0 = time.perf_counter()
32+
s.dropna()
33+
df.dropna()
34+
df.dropna(how="any")
35+
times.append((time.perf_counter() - t0) * 1000)
36+
37+
total_ms = sum(times)
38+
mean_ms = total_ms / ITERATIONS
39+
print(json.dumps({"function": "dropna_fn", "mean_ms": round(mean_ms, 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: pandas Series.explode() / DataFrame.explode() — expand list-like elements.
3+
Outputs JSON: {"function": "explode_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
ROWS = 10_000
11+
WARMUP = 5
12+
ITERATIONS = 20
13+
14+
series_data = [list(range(i * 10 + j for j in range((i % 4) + 2))) for i in range(ROWS)]
15+
series_data = [[i * 10 + j for j in range((i % 4) + 2)] for i in range(ROWS)]
16+
s = pd.Series(series_data)
17+
18+
df = pd.DataFrame({
19+
"a": [[i + j for j in range((i % 3) + 1)] for i in range(ROWS)],
20+
"b": [f"key_{i % 100}" for i in range(ROWS)],
21+
})
22+
23+
for _ in range(WARMUP):
24+
s.explode()
25+
df.explode("a")
26+
27+
times = []
28+
for _ in range(ITERATIONS):
29+
t0 = time.perf_counter()
30+
s.explode()
31+
df.explode("a")
32+
times.append((time.perf_counter() - t0) * 1000)
33+
34+
total_ms = sum(times)
35+
mean_ms = total_ms / ITERATIONS
36+
print(json.dumps({"function": "explode_fn", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""
2+
Benchmark: pandas Series.fillna() / DataFrame.fillna() — fill missing values.
3+
Outputs JSON: {"function": "fillna_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
series_data = [float("nan") if i % 5 == 0 else i * 1.0 for i in range(SIZE)]
15+
s = pd.Series(series_data)
16+
17+
df = pd.DataFrame({
18+
"a": [float("nan") if i % 5 == 0 else i * 0.1 for i in range(SIZE)],
19+
"b": [float("nan") if i % 7 == 0 else i * 2.0 for i in range(SIZE)],
20+
"c": [None if i % 3 == 0 else f"cat{i % 10}" for i in range(SIZE)],
21+
})
22+
23+
for _ in range(WARMUP):
24+
s.fillna(0)
25+
s.fillna(method="ffill")
26+
df.fillna(0)
27+
df.fillna(method="bfill")
28+
29+
times = []
30+
for _ in range(ITERATIONS):
31+
t0 = time.perf_counter()
32+
s.fillna(0)
33+
s.fillna(method="ffill")
34+
df.fillna(0)
35+
df.fillna(method="bfill")
36+
times.append((time.perf_counter() - t0) * 1000)
37+
38+
total_ms = sum(times)
39+
mean_ms = total_ms / ITERATIONS
40+
print(json.dumps({"function": "fillna_fn", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
Benchmark: pandas DataFrame.idxmin() / DataFrame.idxmax() — index of min/max per column.
3+
Outputs JSON: {"function": "idxmin_max_df", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
ROWS = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
df = pd.DataFrame({
15+
"a": [np.sin(i * 0.001) * 100 for i in range(ROWS)],
16+
"b": [float("nan") if i % 100 == 0 else i * 0.1 for i in range(ROWS)],
17+
"c": [i * 1.0 if i % 2 == 0 else -i * 1.0 for i in range(ROWS)],
18+
})
19+
20+
for _ in range(WARMUP):
21+
df.idxmin()
22+
df.idxmax()
23+
df.idxmin(skipna=False)
24+
25+
times = []
26+
for _ in range(ITERATIONS):
27+
t0 = time.perf_counter()
28+
df.idxmin()
29+
df.idxmax()
30+
times.append((time.perf_counter() - t0) * 1000)
31+
32+
total_ms = sum(times)
33+
mean_ms = total_ms / ITERATIONS
34+
print(json.dumps({"function": "idxmin_max_df", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Benchmark: pandas Series.interpolate() / DataFrame.interpolate() — fill NaN by interpolation.
3+
Outputs JSON: {"function": "interpolate_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
SIZE = 50_000
11+
WARMUP = 5
12+
ITERATIONS = 20
13+
14+
series_data = [float("nan") if i % 10 == 0 else i * 1.0 for i in range(SIZE)]
15+
s = pd.Series(series_data)
16+
17+
df = pd.DataFrame({
18+
"a": [float("nan") if i % 7 == 0 else i * 0.5 for i in range(SIZE)],
19+
"b": [float("nan") if i % 11 == 0 else np.sin(i * 0.01) * 100 for i in range(SIZE)],
20+
})
21+
22+
for _ in range(WARMUP):
23+
s.interpolate(method="linear")
24+
s.interpolate(method="pad")
25+
df.interpolate()
26+
27+
times = []
28+
for _ in range(ITERATIONS):
29+
t0 = time.perf_counter()
30+
s.interpolate(method="linear")
31+
s.interpolate(method="pad")
32+
df.interpolate()
33+
times.append((time.perf_counter() - t0) * 1000)
34+
35+
total_ms = sum(times)
36+
mean_ms = total_ms / ITERATIONS
37+
print(json.dumps({"function": "interpolate_fn", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Benchmark: pandas DataFrame.mode() — column-wise mode.
3+
Outputs JSON: {"function": "mode_dataframe_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
ROWS = 10_000
11+
WARMUP = 5
12+
ITERATIONS = 20
13+
14+
df = pd.DataFrame({
15+
"a": [i % 10 for i in range(ROWS)],
16+
"b": [float("nan") if i % 50 == 0 else i % 5 for i in range(ROWS)],
17+
"c": [i % 3 for i in range(ROWS)],
18+
})
19+
20+
for _ in range(WARMUP):
21+
df.mode()
22+
df.mode(dropna=False)
23+
24+
times = []
25+
for _ in range(ITERATIONS):
26+
t0 = time.perf_counter()
27+
df.mode()
28+
df.mode(dropna=False)
29+
times.append((time.perf_counter() - t0) * 1000)
30+
31+
total_ms = sum(times)
32+
mean_ms = total_ms / ITERATIONS
33+
print(json.dumps({"function": "mode_dataframe_fn", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Benchmark: pandas DataFrame.where() / DataFrame.mask() — conditional replacement.
3+
Outputs JSON: {"function": "where_mask_df_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
ROWS = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 20
13+
14+
df = pd.DataFrame({
15+
"a": [i * 1.0 for i in range(ROWS)],
16+
"b": [float("nan") if i % 2 == 0 else i * 0.5 for i in range(ROWS)],
17+
"c": [i * -1.0 for i in range(ROWS)],
18+
})
19+
20+
cond = df > 0
21+
22+
for _ in range(WARMUP):
23+
df.where(cond, other=0)
24+
df.mask(cond, other=-1)
25+
26+
times = []
27+
for _ in range(ITERATIONS):
28+
t0 = time.perf_counter()
29+
df.where(cond, other=0)
30+
df.mask(cond, other=-1)
31+
times.append((time.perf_counter() - t0) * 1000)
32+
33+
total_ms = sum(times)
34+
mean_ms = total_ms / ITERATIONS
35+
print(json.dumps({"function": "where_mask_df_fn", "mean_ms": round(mean_ms, 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+
"""
2+
Benchmark: pandas Series.where() / Series.mask() — conditional replacement.
3+
Outputs JSON: {"function": "where_mask_series_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
import numpy as np
9+
10+
SIZE = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
s = pd.Series([i * 0.1 for i in range(SIZE)])
15+
cond = s > SIZE * 0.05
16+
cond_arr = pd.Series([i > SIZE * 0.5 for i in range(SIZE)])
17+
18+
for _ in range(WARMUP):
19+
s.where(cond, 0)
20+
s.mask(cond_arr, -1)
21+
22+
times = []
23+
for _ in range(ITERATIONS):
24+
t0 = time.perf_counter()
25+
s.where(cond, 0)
26+
s.mask(cond_arr, -1)
27+
times.append((time.perf_counter() - t0) * 1000)
28+
29+
total_ms = sum(times)
30+
mean_ms = total_ms / ITERATIONS
31+
print(json.dumps({"function": "where_mask_series_fn", "mean_ms": round(mean_ms, 3), "iterations": ITERATIONS, "total_ms": round(total_ms, 3)}))
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Benchmark: diffSeries standalone + applymap — diff and element-wise map.
3+
* Outputs JSON: {"function": "diff_applymap_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Series, DataFrame, diffSeries, applymap } from "../../src/index.ts";
6+
7+
const SIZE = 100_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
const s = new Series({ data: Array.from({ length: SIZE }, (_, i) => i * 1.0 + Math.sin(i * 0.01)) });
12+
13+
const df = DataFrame.fromColumns({
14+
a: Array.from({ length: SIZE }, (_, i) => i * 0.1),
15+
b: Array.from({ length: SIZE }, (_, i) => i * 0.2 + 1),
16+
c: Array.from({ length: SIZE }, (_, i) => i * -0.1),
17+
});
18+
19+
for (let i = 0; i < WARMUP; i++) {
20+
diffSeries(s);
21+
diffSeries(s, 2);
22+
applymap(df, (v) => (v as number) ** 2);
23+
}
24+
25+
const times: number[] = [];
26+
for (let i = 0; i < ITERATIONS; i++) {
27+
const t0 = performance.now();
28+
diffSeries(s);
29+
diffSeries(s, 2);
30+
applymap(df, (v) => (v as number) ** 2);
31+
times.push(performance.now() - t0);
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: "diff_applymap_fn",
39+
mean_ms: Math.round(meanMs * 1000) / 1000,
40+
iterations: ITERATIONS,
41+
total_ms: Math.round(totalMs * 1000) / 1000,
42+
}),
43+
);

0 commit comments

Comments
 (0)