Skip to content

Commit 3e89725

Browse files
Iteration 153: Add 5 benchmark pairs (483 total, +5 vs best 478)
Added 5 new benchmark pairs: - datetime_index_ops: DatetimeIndex sort/unique/toStrings/slice/contains/concat - datetime_index_snap: DatetimeIndex.snap(freq) to month-start and week boundaries - period_index_query: PeriodIndex.getLoc/contains querying operations - series_groupby_agg_all: SeriesGroupBy all aggregations (sum/mean/std/min/max/count/first/last) - dataframe_rolling_median: DataFrameRolling.median and DataFrameExpanding.median Run: https://github.com/githubnext/tsessebe/actions/runs/24564770860 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 952d479 commit 3e89725

10 files changed

Lines changed: 415 additions & 0 deletions
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
Benchmark: pandas DataFrame.rolling(10).median() / DataFrame.expanding(1).median() — rolling and expanding median on DataFrame.
3+
Outputs JSON: {"function": "dataframe_rolling_median", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
9+
ROWS = 10_000
10+
WARMUP = 3
11+
ITERATIONS = 20
12+
13+
df = pd.DataFrame({
14+
"a": [i * 0.1 for i in range(ROWS)],
15+
"b": [(i * 0.3) % 500 for i in range(ROWS)],
16+
})
17+
18+
for _ in range(WARMUP):
19+
df.rolling(10).median()
20+
df.expanding(1).median()
21+
22+
times = []
23+
for _ in range(ITERATIONS):
24+
t0 = time.perf_counter()
25+
df.rolling(10).median()
26+
df.expanding(1).median()
27+
times.append((time.perf_counter() - t0) * 1000)
28+
29+
total_ms = sum(times)
30+
mean_ms = total_ms / ITERATIONS
31+
print(json.dumps({
32+
"function": "dataframe_rolling_median",
33+
"mean_ms": round(mean_ms, 3),
34+
"iterations": ITERATIONS,
35+
"total_ms": round(total_ms, 3),
36+
}))
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Benchmark: pandas DatetimeIndex sort_values / unique / strftime / slice / isin / append — DatetimeIndex operations.
3+
Outputs JSON: {"function": "datetime_index_ops", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
9+
SIZE = 10_000
10+
WARMUP = 5
11+
ITERATIONS = 50
12+
13+
idx = pd.date_range(start="2020-01-01", periods=SIZE, freq="h")
14+
idx2 = pd.date_range(start="2021-01-01", periods=SIZE, freq="h")
15+
ref_date = pd.Timestamp("2020-06-15T00:00:00Z")
16+
17+
for _ in range(WARMUP):
18+
idx.sort_values()
19+
idx.unique()
20+
idx.strftime("%Y-%m-%dT%H:%M:%SZ")
21+
idx[:100]
22+
ref_date in idx
23+
idx.append(idx2)
24+
25+
times = []
26+
for _ in range(ITERATIONS):
27+
t0 = time.perf_counter()
28+
idx.sort_values()
29+
idx.unique()
30+
idx.strftime("%Y-%m-%dT%H:%M:%SZ")
31+
idx[:100]
32+
ref_date in idx
33+
idx.append(idx2)
34+
times.append((time.perf_counter() - t0) * 1000)
35+
36+
total_ms = sum(times)
37+
mean_ms = total_ms / ITERATIONS
38+
print(json.dumps({
39+
"function": "datetime_index_ops",
40+
"mean_ms": round(mean_ms, 3),
41+
"iterations": ITERATIONS,
42+
"total_ms": round(total_ms, 3),
43+
}))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
Benchmark: pandas DatetimeIndex.snap(freq) — snap index to frequency boundaries (round to nearest).
3+
Outputs JSON: {"function": "datetime_index_snap", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
9+
SIZE = 5_000
10+
WARMUP = 5
11+
ITERATIONS = 50
12+
13+
# Dates that are not on month/week boundaries
14+
idx = pd.date_range(start="2020-01-15", periods=SIZE, freq="D")
15+
16+
for _ in range(WARMUP):
17+
idx.snap("MS") # snap to month start
18+
idx.snap("W") # snap to week
19+
20+
times = []
21+
for _ in range(ITERATIONS):
22+
t0 = time.perf_counter()
23+
idx.snap("MS")
24+
idx.snap("W")
25+
times.append((time.perf_counter() - t0) * 1000)
26+
27+
total_ms = sum(times)
28+
mean_ms = total_ms / ITERATIONS
29+
print(json.dumps({
30+
"function": "datetime_index_snap",
31+
"mean_ms": round(mean_ms, 3),
32+
"iterations": ITERATIONS,
33+
"total_ms": round(total_ms, 3),
34+
}))
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Benchmark: pandas PeriodIndex.get_loc / isin — querying a PeriodIndex.
3+
Outputs JSON: {"function": "period_index_query", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
"""
5+
import json
6+
import time
7+
import pandas as pd
8+
9+
SIZE = 1_000
10+
WARMUP = 5
11+
ITERATIONS = 100
12+
13+
base = pd.Period("2020-01", freq="M")
14+
periods = [base + i for i in range(SIZE)]
15+
idx = pd.PeriodIndex(periods)
16+
17+
query_period = base + 500
18+
mid_period = base + 250
19+
20+
for _ in range(WARMUP):
21+
idx.get_loc(query_period)
22+
query_period in idx
23+
idx.get_loc(mid_period)
24+
mid_period in idx
25+
26+
times = []
27+
for _ in range(ITERATIONS):
28+
t0 = time.perf_counter()
29+
idx.get_loc(query_period)
30+
query_period in idx
31+
idx.get_loc(mid_period)
32+
mid_period in idx
33+
times.append((time.perf_counter() - t0) * 1000)
34+
35+
total_ms = sum(times)
36+
mean_ms = total_ms / ITERATIONS
37+
print(json.dumps({
38+
"function": "period_index_query",
39+
"mean_ms": round(mean_ms, 3),
40+
"iterations": ITERATIONS,
41+
"total_ms": round(total_ms, 3),
42+
}))
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Benchmark: pandas SeriesGroupBy — all aggregation operations (sum/mean/std/min/max/count/first/last) on 100k Series.
3+
Outputs JSON: {"function": "series_groupby_agg_all", "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 = 3
12+
ITERATIONS = 10
13+
14+
s = pd.Series((np.arange(SIZE) * 1.5) % 9999)
15+
by = pd.Series(np.arange(SIZE) % 100)
16+
gb = s.groupby(by)
17+
18+
for _ in range(WARMUP):
19+
gb.sum()
20+
gb.mean()
21+
gb.std()
22+
gb.min()
23+
gb.max()
24+
gb.count()
25+
gb.first()
26+
gb.last()
27+
28+
times = []
29+
for _ in range(ITERATIONS):
30+
t0 = time.perf_counter()
31+
gb.sum()
32+
gb.mean()
33+
gb.std()
34+
gb.min()
35+
gb.max()
36+
gb.count()
37+
gb.first()
38+
gb.last()
39+
times.append((time.perf_counter() - t0) * 1000)
40+
41+
total_ms = sum(times)
42+
mean_ms = total_ms / ITERATIONS
43+
print(json.dumps({
44+
"function": "series_groupby_agg_all",
45+
"mean_ms": round(mean_ms, 3),
46+
"iterations": ITERATIONS,
47+
"total_ms": round(total_ms, 3),
48+
}))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Benchmark: DataFrameRolling.median / DataFrameExpanding.median — rolling and expanding median on DataFrame.
3+
* Outputs JSON: {"function": "dataframe_rolling_median", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { DataFrame } from "../../src/index.ts";
6+
7+
const ROWS = 10_000;
8+
const WARMUP = 3;
9+
const ITERATIONS = 20;
10+
11+
const df = DataFrame.fromColumns({
12+
a: Array.from({ length: ROWS }, (_, i) => i * 0.1),
13+
b: Array.from({ length: ROWS }, (_, i) => (i * 0.3) % 500),
14+
});
15+
16+
for (let i = 0; i < WARMUP; i++) {
17+
df.rolling(10).median();
18+
df.expanding(1).median();
19+
}
20+
21+
const times: number[] = [];
22+
for (let i = 0; i < ITERATIONS; i++) {
23+
const t0 = performance.now();
24+
df.rolling(10).median();
25+
df.expanding(1).median();
26+
times.push(performance.now() - t0);
27+
}
28+
29+
const totalMs = times.reduce((a, b) => a + b, 0);
30+
const meanMs = totalMs / ITERATIONS;
31+
console.log(
32+
JSON.stringify({
33+
function: "dataframe_rolling_median",
34+
mean_ms: Math.round(meanMs * 1000) / 1000,
35+
iterations: ITERATIONS,
36+
total_ms: Math.round(totalMs * 1000) / 1000,
37+
}),
38+
);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Benchmark: DatetimeIndex sort / unique / toStrings / slice / contains / concat — DatetimeIndex operations.
3+
* Outputs JSON: {"function": "datetime_index_ops", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { date_range } from "../../src/index.ts";
6+
7+
const SIZE = 10_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 50;
10+
11+
const idx = date_range({ start: "2020-01-01", periods: SIZE, freq: "h" });
12+
const idx2 = date_range({ start: "2021-01-01", periods: SIZE, freq: "h" });
13+
const refDate = new Date("2020-06-15T00:00:00Z");
14+
15+
for (let i = 0; i < WARMUP; i++) {
16+
idx.sort();
17+
idx.unique();
18+
idx.toStrings();
19+
idx.slice(0, 100);
20+
idx.contains(refDate);
21+
idx.concat(idx2);
22+
}
23+
24+
const times: number[] = [];
25+
for (let i = 0; i < ITERATIONS; i++) {
26+
const t0 = performance.now();
27+
idx.sort();
28+
idx.unique();
29+
idx.toStrings();
30+
idx.slice(0, 100);
31+
idx.contains(refDate);
32+
idx.concat(idx2);
33+
times.push(performance.now() - t0);
34+
}
35+
36+
const totalMs = times.reduce((a, b) => a + b, 0);
37+
const meanMs = totalMs / ITERATIONS;
38+
console.log(
39+
JSON.stringify({
40+
function: "datetime_index_ops",
41+
mean_ms: Math.round(meanMs * 1000) / 1000,
42+
iterations: ITERATIONS,
43+
total_ms: Math.round(totalMs * 1000) / 1000,
44+
}),
45+
);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Benchmark: DatetimeIndex.snap(freq) — snap index dates to frequency boundaries.
3+
* Outputs JSON: {"function": "datetime_index_snap", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { date_range } from "../../src/index.ts";
6+
7+
const SIZE = 5_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 50;
10+
11+
// Dates that are not on month/week boundaries
12+
const idx = date_range({ start: "2020-01-15", periods: SIZE, freq: "D" });
13+
14+
for (let i = 0; i < WARMUP; i++) {
15+
idx.snap("MS"); // snap to month start
16+
idx.snap("W"); // snap to week
17+
}
18+
19+
const times: number[] = [];
20+
for (let i = 0; i < ITERATIONS; i++) {
21+
const t0 = performance.now();
22+
idx.snap("MS");
23+
idx.snap("W");
24+
times.push(performance.now() - t0);
25+
}
26+
27+
const totalMs = times.reduce((a, b) => a + b, 0);
28+
const meanMs = totalMs / ITERATIONS;
29+
console.log(
30+
JSON.stringify({
31+
function: "datetime_index_snap",
32+
mean_ms: Math.round(meanMs * 1000) / 1000,
33+
iterations: ITERATIONS,
34+
total_ms: Math.round(totalMs * 1000) / 1000,
35+
}),
36+
);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Benchmark: PeriodIndex.getLoc / contains — querying a PeriodIndex.
3+
* Outputs JSON: {"function": "period_index_query", "mean_ms": ..., "iterations": ..., "total_ms": ...}
4+
*/
5+
import { Period, PeriodIndex } from "../../src/index.ts";
6+
7+
const SIZE = 1_000;
8+
const WARMUP = 5;
9+
const ITERATIONS = 100;
10+
11+
const base = Period.fromDate(new Date(Date.UTC(2020, 0, 1)), "M");
12+
const periods = Array.from({ length: SIZE }, (_, i) => base.add(i));
13+
const idx = PeriodIndex.fromPeriods(periods);
14+
15+
const queryPeriod = base.add(500);
16+
const midPeriod = base.add(250);
17+
18+
for (let i = 0; i < WARMUP; i++) {
19+
idx.getLoc(queryPeriod);
20+
idx.contains(queryPeriod);
21+
idx.getLoc(midPeriod);
22+
idx.contains(midPeriod);
23+
}
24+
25+
const times: number[] = [];
26+
for (let i = 0; i < ITERATIONS; i++) {
27+
const t0 = performance.now();
28+
idx.getLoc(queryPeriod);
29+
idx.contains(queryPeriod);
30+
idx.getLoc(midPeriod);
31+
idx.contains(midPeriod);
32+
times.push(performance.now() - t0);
33+
}
34+
35+
const totalMs = times.reduce((a, b) => a + b, 0);
36+
const meanMs = totalMs / ITERATIONS;
37+
console.log(
38+
JSON.stringify({
39+
function: "period_index_query",
40+
mean_ms: Math.round(meanMs * 1000) / 1000,
41+
iterations: ITERATIONS,
42+
total_ms: Math.round(totalMs * 1000) / 1000,
43+
}),
44+
);

0 commit comments

Comments
 (0)