Skip to content

Commit 4da5bd5

Browse files
Iteration 261: 7 more benchmark pairs (621 total)
Run: https://github.com/githubnext/tsessebe/actions/runs/24683090417 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f3da892 commit 4da5bd5

14 files changed

Lines changed: 571 additions & 0 deletions
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Benchmark: number formatting operations (float, percent, scientific, etc.).
2+
Mirrors tsb bench_format_ops_fn.ts using Python format functions.
3+
"""
4+
import json, time
5+
6+
SIZE = 10_000
7+
WARMUP = 5
8+
ITERATIONS = 50
9+
10+
values = [i * 1234.567 + 0.001 for i in range(SIZE)]
11+
12+
def fmt_float(v, decimals=6): return f"{v:.{decimals}f}"
13+
def fmt_percent(v, decimals=2): return f"{v:.{decimals}%}"
14+
def fmt_scientific(v, decimals=6): return f"{v:.{decimals}e}"
15+
def fmt_engineering(v): return f"{v:.6g}"
16+
def fmt_thousands(v): return f"{v:,.2f}"
17+
def fmt_currency(v): return f"${v:,.2f}"
18+
def fmt_compact(v):
19+
if abs(v) >= 1e9: return f"{v/1e9:.1f}B"
20+
if abs(v) >= 1e6: return f"{v/1e6:.1f}M"
21+
if abs(v) >= 1e3: return f"{v/1e3:.1f}K"
22+
return f"{v:.1f}"
23+
24+
for _ in range(WARMUP):
25+
for v in values[:100]:
26+
fmt_float(v, 2)
27+
fmt_percent(v / 100_000, 1)
28+
fmt_scientific(v, 3)
29+
30+
start = time.perf_counter()
31+
for _ in range(ITERATIONS):
32+
for v in values:
33+
fmt_float(v, 2)
34+
fmt_percent(v / 100_000, 1)
35+
fmt_scientific(v, 3)
36+
fmt_engineering(v)
37+
fmt_thousands(v)
38+
fmt_currency(v)
39+
fmt_compact(v)
40+
total = (time.perf_counter() - start) * 1000
41+
42+
print(json.dumps({
43+
"function": "format_ops_fn",
44+
"mean_ms": round(total / ITERATIONS, 3),
45+
"iterations": ITERATIONS,
46+
"total_ms": round(total, 3),
47+
}))
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Benchmark: formatter factory functions — make formatters and apply to series/dataframe.
2+
Mirrors tsb bench_formatter_factories_fn.ts using pandas styling/format.
3+
"""
4+
import json, time
5+
import pandas as pd
6+
import numpy as np
7+
8+
SIZE = 10_000
9+
WARMUP = 5
10+
ITERATIONS = 50
11+
12+
ser = pd.Series(np.arange(SIZE) * 1.23456)
13+
df = pd.DataFrame({
14+
"price": np.arange(SIZE) * 9.99,
15+
"pct": (np.arange(SIZE) % 100) / 100,
16+
})
17+
18+
def fmt_float(decimals): return lambda v: f"{v:.{decimals}f}"
19+
def fmt_pct(decimals): return lambda v: f"{v:.{decimals}%}"
20+
def fmt_cur(symbol, decimals): return lambda v: f"{symbol}{v:,.{decimals}f}"
21+
22+
for _ in range(WARMUP):
23+
ff = fmt_float(2)
24+
ser.map(ff)
25+
fc = fmt_cur("$", 2)
26+
fp = fmt_pct(1)
27+
df.apply(lambda col: col.map(fc if col.name == "price" else fp))
28+
29+
start = time.perf_counter()
30+
for _ in range(ITERATIONS):
31+
fmt_float(3)
32+
fmt_pct(2)
33+
fmt_cur("€", 2)
34+
ff = fmt_float(2)
35+
fc = fmt_cur("$", 2)
36+
fp = fmt_pct(1)
37+
ser.map(ff)
38+
df.apply(lambda col: col.map(fc if col.name == "price" else fp))
39+
total = (time.perf_counter() - start) * 1000
40+
41+
print(json.dumps({
42+
"function": "formatter_factories_fn",
43+
"mean_ms": round(total / ITERATIONS, 3),
44+
"iterations": ITERATIONS,
45+
"total_ms": round(total, 3),
46+
}))
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Benchmark: nunique standalone — count unique values in DataFrame with DataFrame.nunique().
2+
Mirrors tsb bench_nunique_standalone_fn.ts.
3+
"""
4+
import json, time
5+
import pandas as pd
6+
import numpy as np
7+
8+
ROWS = 50_000
9+
WARMUP = 5
10+
ITERATIONS = 30
11+
12+
df = pd.DataFrame({
13+
"a": np.arange(ROWS) % 1_000,
14+
"b": [f"cat_{i % 200}" for i in range(ROWS)],
15+
"c": np.arange(ROWS) % 50,
16+
"d": [float(i % 100) if i % 5 != 0 else np.nan for i in range(ROWS)],
17+
})
18+
19+
for _ in range(WARMUP):
20+
df.nunique()
21+
df.nunique(axis=1)
22+
23+
start = time.perf_counter()
24+
for _ in range(ITERATIONS):
25+
df.nunique()
26+
df.nunique(dropna=False)
27+
df.nunique(axis=1)
28+
total = (time.perf_counter() - start) * 1000
29+
30+
print(json.dumps({
31+
"function": "nunique_standalone_fn",
32+
"mean_ms": round(total / ITERATIONS, 3),
33+
"iterations": ITERATIONS,
34+
"total_ms": round(total, 3),
35+
}))
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Benchmark: Series + DataFrame string representations using pandas .to_string().
2+
Mirrors tsb bench_series_dataframe_to_string.ts.
3+
"""
4+
import json, time
5+
import pandas as pd
6+
import numpy as np
7+
8+
ROWS = 1_000
9+
WARMUP = 5
10+
ITERATIONS = 100
11+
12+
ser = pd.Series(np.arange(ROWS) * 3.14159, name="values")
13+
df = pd.DataFrame({
14+
"a": np.arange(ROWS) * 1.5,
15+
"b": [f"cat_{i % 20}" for i in range(ROWS)],
16+
"c": np.arange(ROWS) % 100,
17+
})
18+
19+
for _ in range(WARMUP):
20+
ser.to_string()
21+
ser.head(10).to_string()
22+
df.to_string(max_rows=20)
23+
24+
start = time.perf_counter()
25+
for _ in range(ITERATIONS):
26+
ser.to_string()
27+
ser.head(10).to_string()
28+
df.to_string()
29+
df.to_string(max_rows=20)
30+
total = (time.perf_counter() - start) * 1000
31+
32+
print(json.dumps({
33+
"function": "series_dataframe_to_string",
34+
"mean_ms": round(total / ITERATIONS, 3),
35+
"iterations": ITERATIONS,
36+
"total_ms": round(total, 3),
37+
}))
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Benchmark: SeriesGroupBy get_group — retrieve specific groups by key.
2+
Mirrors tsb bench_series_groupby_getgroup_fn.ts using pandas SeriesGroupBy.
3+
"""
4+
import json, time
5+
import pandas as pd
6+
import numpy as np
7+
8+
ROWS = 100_000
9+
N_GROUPS = 50
10+
WARMUP = 5
11+
ITERATIONS = 100
12+
13+
keys = [f"group_{i % N_GROUPS}" for i in range(ROWS)]
14+
values = np.arange(ROWS) * 1.5
15+
ser = pd.Series(values)
16+
sgb = ser.groupby(keys)
17+
18+
group_keys = [f"group_{i}" for i in range(N_GROUPS)]
19+
20+
for _ in range(WARMUP):
21+
for k in group_keys:
22+
sgb.get_group(k)
23+
24+
start = time.perf_counter()
25+
for _ in range(ITERATIONS):
26+
for k in group_keys:
27+
sgb.get_group(k)
28+
total = (time.perf_counter() - start) * 1000
29+
30+
print(json.dumps({
31+
"function": "series_groupby_getgroup_fn",
32+
"mean_ms": round(total / ITERATIONS, 3),
33+
"iterations": ITERATIONS,
34+
"total_ms": round(total, 3),
35+
}))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Benchmark: Timestamp tz_localize + tz_convert — timezone ops on individual Timestamps.
2+
Mirrors tsb bench_timestamp_tz_ops.ts using pandas Timestamp.
3+
"""
4+
import json, time
5+
import pandas as pd
6+
7+
SIZE = 5_000
8+
WARMUP = 5
9+
ITERATIONS = 50
10+
11+
timestamps = [
12+
pd.Timestamp(year=2020, month=1 + (i % 12), day=1 + (i % 28), hour=i % 24, minute=i % 60, second=0)
13+
for i in range(SIZE)
14+
]
15+
16+
for _ in range(WARMUP):
17+
for ts in timestamps[:100]:
18+
ts_utc = ts.tz_localize("UTC")
19+
ts_utc.tz_convert("America/New_York")
20+
21+
start = time.perf_counter()
22+
for _ in range(ITERATIONS):
23+
for ts in timestamps:
24+
ts_utc = ts.tz_localize("UTC")
25+
ts_ny = ts_utc.tz_convert("America/New_York")
26+
ts_ny.tz_convert("Europe/London")
27+
total = (time.perf_counter() - start) * 1000
28+
29+
print(json.dumps({
30+
"function": "timestamp_tz_ops",
31+
"mean_ms": round(total / ITERATIONS, 3),
32+
"iterations": ITERATIONS,
33+
"total_ms": round(total, 3),
34+
}))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Benchmark: toDateInput — normalize various date inputs using pandas Timestamp.
2+
Mirrors tsb bench_to_date_input_fn.ts.
3+
"""
4+
import json, time
5+
import pandas as pd
6+
7+
SIZE = 50_000
8+
WARMUP = 5
9+
ITERATIONS = 50
10+
11+
strings = [f"2020-{1 + (i % 12):02d}-01" for i in range(SIZE)]
12+
timestamps = [int((pd.Timestamp("2020-01-01").timestamp() + i * 86400) * 1000) for i in range(SIZE)]
13+
dates = [pd.Timestamp(2020, 1 + (i % 12), 1 + (i % 28)) for i in range(SIZE)]
14+
15+
for _ in range(WARMUP):
16+
for s in strings[:100]:
17+
pd.Timestamp(s)
18+
for t in timestamps[:100]:
19+
pd.Timestamp(t, unit="ms")
20+
for d in dates[:100]:
21+
pd.Timestamp(d)
22+
23+
start = time.perf_counter()
24+
for _ in range(ITERATIONS):
25+
for s in strings:
26+
pd.Timestamp(s)
27+
for t in timestamps:
28+
pd.Timestamp(t, unit="ms")
29+
for d in dates:
30+
pd.Timestamp(d)
31+
total = (time.perf_counter() - start) * 1000
32+
33+
print(json.dumps({
34+
"function": "to_date_input_fn",
35+
"mean_ms": round(total / ITERATIONS, 3),
36+
"iterations": ITERATIONS,
37+
"total_ms": round(total, 3),
38+
}))
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Benchmark: dataFrameToString + seriesToString with float formatting options.
3+
* Outputs JSON: {"function": "format_ops_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import {
6+
Series,
7+
formatFloat,
8+
formatPercent,
9+
formatScientific,
10+
formatEngineering,
11+
formatThousands,
12+
formatCurrency,
13+
formatCompact,
14+
} from "../../src/index.ts";
15+
16+
const SIZE = 10_000;
17+
const WARMUP = 5;
18+
const ITERATIONS = 50;
19+
20+
const values = Array.from({ length: SIZE }, (_, i) => i * 1234.567 + 0.001);
21+
22+
for (let i = 0; i < WARMUP; i++) {
23+
for (const v of values.slice(0, 100)) {
24+
formatFloat(v);
25+
formatPercent(v / 100_000);
26+
formatScientific(v);
27+
}
28+
}
29+
30+
const start = performance.now();
31+
for (let i = 0; i < ITERATIONS; i++) {
32+
for (const v of values) {
33+
formatFloat(v, 2);
34+
formatPercent(v / 100_000, 1);
35+
formatScientific(v, 3);
36+
formatEngineering(v);
37+
formatThousands(v);
38+
formatCurrency(v);
39+
formatCompact(v);
40+
}
41+
}
42+
const total = performance.now() - start;
43+
44+
console.log(
45+
JSON.stringify({
46+
function: "format_ops_fn",
47+
mean_ms: Math.round((total / ITERATIONS) * 1000) / 1000,
48+
iterations: ITERATIONS,
49+
total_ms: Math.round(total * 1000) / 1000,
50+
}),
51+
);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Benchmark: makeFloatFormatter + makePercentFormatter + makeCurrencyFormatter — formatter factories.
3+
* Outputs JSON: {"function": "formatter_factories_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import {
6+
Series,
7+
makeFloatFormatter,
8+
makePercentFormatter,
9+
makeCurrencyFormatter,
10+
applySeriesFormatter,
11+
applyDataFrameFormatter,
12+
DataFrame,
13+
} from "../../src/index.ts";
14+
15+
const SIZE = 10_000;
16+
const WARMUP = 5;
17+
const ITERATIONS = 50;
18+
19+
const ser = new Series(Array.from({ length: SIZE }, (_, i) => i * 1.23456));
20+
const df = DataFrame.fromColumns({
21+
price: Array.from({ length: SIZE }, (_, i) => i * 9.99),
22+
pct: Array.from({ length: SIZE }, (_, i) => (i % 100) / 100),
23+
});
24+
25+
const fmtFloat = makeFloatFormatter(2);
26+
const fmtPct = makePercentFormatter(1);
27+
const fmtCur = makeCurrencyFormatter("$", 2);
28+
29+
for (let i = 0; i < WARMUP; i++) {
30+
applySeriesFormatter(ser, fmtFloat);
31+
applyDataFrameFormatter(df, { price: fmtCur, pct: fmtPct });
32+
}
33+
34+
const start = performance.now();
35+
for (let i = 0; i < ITERATIONS; i++) {
36+
makeFloatFormatter(3);
37+
makePercentFormatter(2);
38+
makeCurrencyFormatter("€", 2);
39+
applySeriesFormatter(ser, fmtFloat);
40+
applyDataFrameFormatter(df, { price: fmtCur, pct: fmtPct });
41+
}
42+
const total = performance.now() - start;
43+
44+
console.log(
45+
JSON.stringify({
46+
function: "formatter_factories_fn",
47+
mean_ms: Math.round((total / ITERATIONS) * 1000) / 1000,
48+
iterations: ITERATIONS,
49+
total_ms: Math.round(total * 1000) / 1000,
50+
}),
51+
);

0 commit comments

Comments
 (0)