Skip to content

Commit 26437c0

Browse files
Iteration 138: Add 8 benchmark pairs (412 total, +8 vs 404)
Added benchmarks for: - series_ceil_floor_trunc_sqrt: seriesCeil/seriesFloor/seriesTrunc/seriesSqrt vs numpy - dataframe_ceil_floor_trunc: dataFrameCeil/Floor/Trunc/Sqrt vs numpy on DataFrame - dataframe_exp_log: dataFrameExp/Log/Log2/Log10 vs numpy on DataFrame - pivot_table_full: pivotTableFull (with margins) vs pd.pivot_table - read_excel: readExcel/xlsxSheetNames with 10k-row XLSX vs pd.read_excel/openpyxl - pipe_chain_ops: pipeChain/pipeTo/dataFramePipeChain/dataFramePipeTo vs .pipe() - nan_extended_agg: nancount/nanmedian/nanprod vs Series.count/median/prod - series_pipe_apply: pipeSeries/dataFramePipe vs Series.pipe/DataFrame.pipe Run: https://github.com/githubnext/tsessebe/actions/runs/24538933188 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3165c28 commit 26437c0

16 files changed

Lines changed: 741 additions & 0 deletions
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Benchmark: DataFrame ceil / floor / trunc / sqrt — math rounding on 100k-row DataFrame.
3+
Outputs JSON: {"function": "dataframe_ceil_floor_trunc", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
ROWS = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
df = pd.DataFrame({
15+
"a": (np.arange(ROWS) % 1000) * 0.7 + 0.3,
16+
"b": (np.arange(ROWS) % 500) * 1.3 + 0.1,
17+
})
18+
19+
for _ in range(WARMUP):
20+
np.ceil(df)
21+
np.floor(df)
22+
np.trunc(df)
23+
np.sqrt(df)
24+
25+
start = time.perf_counter()
26+
for _ in range(ITERATIONS):
27+
np.ceil(df)
28+
np.floor(df)
29+
np.trunc(df)
30+
np.sqrt(df)
31+
total = (time.perf_counter() - start) * 1000
32+
33+
print(json.dumps({
34+
"function": "dataframe_ceil_floor_trunc",
35+
"mean_ms": total / ITERATIONS,
36+
"iterations": ITERATIONS,
37+
"total_ms": total,
38+
}))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Benchmark: DataFrame exp / log / log2 / log10 — exponentiation/log on 100k-row DataFrame.
3+
Outputs JSON: {"function": "dataframe_exp_log", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
ROWS = 100_000
11+
WARMUP = 5
12+
ITERATIONS = 30
13+
14+
df = pd.DataFrame({
15+
"a": (np.arange(ROWS) % 1000) + 1,
16+
"b": (np.arange(ROWS) % 500) + 1,
17+
})
18+
19+
for _ in range(WARMUP):
20+
np.exp(df)
21+
np.log(df)
22+
np.log2(df)
23+
np.log10(df)
24+
25+
start = time.perf_counter()
26+
for _ in range(ITERATIONS):
27+
np.exp(df)
28+
np.log(df)
29+
np.log2(df)
30+
np.log10(df)
31+
total = (time.perf_counter() - start) * 1000
32+
33+
print(json.dumps({
34+
"function": "dataframe_exp_log",
35+
"mean_ms": total / ITERATIONS,
36+
"iterations": ITERATIONS,
37+
"total_ms": total,
38+
}))
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Benchmark: count/median/prod nan-ignoring aggregates on 100k-element array.
3+
Outputs JSON: {"function": "nan_extended_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 = 50
13+
14+
# Array with ~10% NaN values; small values to avoid prod overflow
15+
data = np.where(
16+
np.arange(SIZE) % 10 == 0,
17+
np.nan,
18+
(np.arange(SIZE) % 100) * 0.01 + 1,
19+
)
20+
s = pd.Series(data)
21+
22+
for _ in range(WARMUP):
23+
s.count()
24+
s.median(skipna=True)
25+
s.prod(skipna=True)
26+
27+
start = time.perf_counter()
28+
for _ in range(ITERATIONS):
29+
s.count()
30+
s.median(skipna=True)
31+
s.prod(skipna=True)
32+
total = (time.perf_counter() - start) * 1000
33+
34+
print(json.dumps({
35+
"function": "nan_extended_agg",
36+
"mean_ms": total / ITERATIONS,
37+
"iterations": ITERATIONS,
38+
"total_ms": total,
39+
}))
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
Benchmark: pipe chaining utilities — pipeChain / pipeTo / dataFramePipeChain / dataFramePipeTo.
3+
Outputs JSON: {"function": "pipe_chain_ops", "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+
s = pd.Series(np.arange(SIZE) * 0.5 - SIZE * 0.25)
15+
df = pd.DataFrame({
16+
"a": np.arange(SIZE) * 0.5,
17+
"b": np.arange(SIZE) * 0.3 + 1,
18+
})
19+
20+
def double(x): return x * 2
21+
def add_one(x): return x + 1
22+
def abs_val(x): return x.abs()
23+
24+
# pandas equivalent of pipeChain: .pipe(fn1).pipe(fn2).pipe(fn3)
25+
# pandas equivalent of pipeTo: .pipe(fn, *args) with positional arg
26+
27+
for _ in range(WARMUP):
28+
s.pipe(double).pipe(add_one).pipe(abs_val)
29+
s.pipe(abs_val)
30+
df.pipe(double).pipe(abs_val)
31+
df.pipe(abs_val)
32+
33+
start = time.perf_counter()
34+
for _ in range(ITERATIONS):
35+
s.pipe(double).pipe(add_one).pipe(abs_val)
36+
s.pipe(abs_val)
37+
df.pipe(double).pipe(abs_val)
38+
df.pipe(abs_val)
39+
total = (time.perf_counter() - start) * 1000
40+
41+
print(json.dumps({
42+
"function": "pipe_chain_ops",
43+
"mean_ms": total / ITERATIONS,
44+
"iterations": ITERATIONS,
45+
"total_ms": total,
46+
}))
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
Benchmark: pivot_table with margins on 50k-row DataFrame.
3+
Outputs JSON: {"function": "pivot_table_full", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import numpy as np
8+
import pandas as pd
9+
10+
ROWS = 50_000
11+
WARMUP = 3
12+
ITERATIONS = 20
13+
14+
regions = ["North", "South", "East", "West"]
15+
products = ["A", "B", "C", "D", "E"]
16+
17+
df = pd.DataFrame({
18+
"region": [regions[i % len(regions)] for i in range(ROWS)],
19+
"product": [products[i % len(products)] for i in range(ROWS)],
20+
"sales": (np.arange(ROWS) % 1000) * 1.5 + 10,
21+
})
22+
23+
for _ in range(WARMUP):
24+
pd.pivot_table(df, values="sales", index="region", columns="product", aggfunc="mean", margins=True)
25+
26+
start = time.perf_counter()
27+
for _ in range(ITERATIONS):
28+
pd.pivot_table(df, values="sales", index="region", columns="product", aggfunc="mean", margins=True)
29+
total = (time.perf_counter() - start) * 1000
30+
31+
print(json.dumps({
32+
"function": "pivot_table_full",
33+
"mean_ms": total / ITERATIONS,
34+
"iterations": ITERATIONS,
35+
"total_ms": total,
36+
}))
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Benchmark: pd.read_excel / ExcelFile.sheet_names — parse a 10k-row XLSX file.
3+
Outputs JSON: {"function": "read_excel", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import io
8+
import numpy as np
9+
import pandas as pd
10+
11+
try:
12+
import openpyxl
13+
except ImportError:
14+
import subprocess, sys
15+
subprocess.check_call([sys.executable, "-m", "pip", "install", "openpyxl", "--quiet"])
16+
import openpyxl
17+
18+
ROWS = 10_000
19+
WARMUP = 3
20+
ITERATIONS = 10
21+
22+
# Build an XLSX file in memory using openpyxl
23+
wb = openpyxl.Workbook()
24+
ws = wb.active
25+
ws.title = "Sheet1"
26+
ws.append(["id", "name", "value", "score"])
27+
for i in range(ROWS):
28+
ws.append([i, f"item_{i % 100}", i * 1.5, float(np.sin(i * 0.01))])
29+
30+
buf = io.BytesIO()
31+
wb.save(buf)
32+
xlsx_bytes = buf.getvalue()
33+
34+
for _ in range(WARMUP):
35+
pd.read_excel(io.BytesIO(xlsx_bytes), engine="openpyxl")
36+
pd.ExcelFile(io.BytesIO(xlsx_bytes), engine="openpyxl").sheet_names
37+
38+
start = time.perf_counter()
39+
for _ in range(ITERATIONS):
40+
pd.read_excel(io.BytesIO(xlsx_bytes), engine="openpyxl")
41+
pd.ExcelFile(io.BytesIO(xlsx_bytes), engine="openpyxl").sheet_names
42+
total = (time.perf_counter() - start) * 1000
43+
44+
print(json.dumps({
45+
"function": "read_excel",
46+
"mean_ms": total / ITERATIONS,
47+
"iterations": ITERATIONS,
48+
"total_ms": total,
49+
}))
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Benchmark: Series ceil / floor / trunc / sqrt — math rounding on 100k-element Series.
3+
Outputs JSON: {"function": "series_ceil_floor_trunc_sqrt", "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+
s = pd.Series((np.arange(SIZE) % 1000) * 0.7 + 0.3)
15+
16+
for _ in range(WARMUP):
17+
np.ceil(s)
18+
np.floor(s)
19+
np.trunc(s)
20+
np.sqrt(s)
21+
22+
start = time.perf_counter()
23+
for _ in range(ITERATIONS):
24+
np.ceil(s)
25+
np.floor(s)
26+
np.trunc(s)
27+
np.sqrt(s)
28+
total = (time.perf_counter() - start) * 1000
29+
30+
print(json.dumps({
31+
"function": "series_ceil_floor_trunc_sqrt",
32+
"mean_ms": total / ITERATIONS,
33+
"iterations": ITERATIONS,
34+
"total_ms": total,
35+
}))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Benchmark: Series.pipe / DataFrame.pipe — pipe function application utilities.
3+
Outputs JSON: {"function": "series_pipe_apply", "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+
s = pd.Series(np.arange(SIZE) * 0.5 - SIZE * 0.25)
15+
df = pd.DataFrame({
16+
"a": np.arange(SIZE) * 0.5,
17+
"b": np.arange(SIZE) * 0.3 + 1,
18+
})
19+
20+
def abs_and_double(x):
21+
return x.abs() * 2
22+
23+
for _ in range(WARMUP):
24+
s.pipe(abs_and_double)
25+
df.pipe(abs_and_double)
26+
27+
start = time.perf_counter()
28+
for _ in range(ITERATIONS):
29+
s.pipe(abs_and_double)
30+
df.pipe(abs_and_double)
31+
total = (time.perf_counter() - start) * 1000
32+
33+
print(json.dumps({
34+
"function": "series_pipe_apply",
35+
"mean_ms": total / ITERATIONS,
36+
"iterations": ITERATIONS,
37+
"total_ms": total,
38+
}))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Benchmark: dataFrameCeil / dataFrameFloor / dataFrameTrunc / dataFrameSqrt — math rounding on 100k-row DataFrame.
3+
* Outputs JSON: {"function": "dataframe_ceil_floor_trunc", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame, dataFrameCeil, dataFrameFloor, dataFrameTrunc, dataFrameSqrt } from "../../src/index.ts";
6+
7+
const ROWS = 100_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 30;
10+
11+
const a = Array.from({ length: ROWS }, (_, i) => (i % 1000) * 0.7 + 0.3);
12+
const b = Array.from({ length: ROWS }, (_, i) => (i % 500) * 1.3 + 0.1);
13+
const df = DataFrame.fromColumns({ a, b });
14+
15+
for (let i = 0; i < WARMUP; i++) {
16+
dataFrameCeil(df);
17+
dataFrameFloor(df);
18+
dataFrameTrunc(df);
19+
dataFrameSqrt(df);
20+
}
21+
22+
const start = performance.now();
23+
for (let i = 0; i < ITERATIONS; i++) {
24+
dataFrameCeil(df);
25+
dataFrameFloor(df);
26+
dataFrameTrunc(df);
27+
dataFrameSqrt(df);
28+
}
29+
const total = performance.now() - start;
30+
31+
console.log(
32+
JSON.stringify({
33+
function: "dataframe_ceil_floor_trunc",
34+
mean_ms: total / ITERATIONS,
35+
iterations: ITERATIONS,
36+
total_ms: total,
37+
}),
38+
);

0 commit comments

Comments
 (0)