Dask, for logs over four million rows#
clvkit stays small by default: the four runtime dependencies and nothing else.
CustomerBase.from_transactions is the one step whose cost scales with
transactions rather than customers, so it’s the only place a second engine is
offered:
uv add "clvkit[dask]"
Pass engine="dask" to CustomerBase.from_transactions with a
dask.dataframe.DataFrame in place of the pandas one. The summary it returns
is an ordinary small pandas-backed CustomerBase all the same.
Where it starts to win#
Synthetic logs in the input contract, read from Parquet by both engines and
summarised at time_unit="W", collapse="D" on a 10-core M-series MacBook Pro.
Three transactions per customer, a CDNOW-shaped log:
rows |
pandas |
Dask |
|
|---|---|---|---|
100,000 |
0.06 s · 192 MB |
0.22 s · 216 MB |
pandas 3.7× faster |
1,000,000 |
0.35 s · 474 MB |
0.50 s · 556 MB |
pandas 1.4× faster |
4,000,000 |
1.99 s · 1,349 MB |
1.68 s · 1,698 MB |
Dask 1.2× faster |
16,000,000 |
17.40 s · 4,973 MB |
9.59 s · 5,589 MB |
Dask 1.8× faster |
When to reach for it#
The crossover is at about four million transactions. Below it, Dask’s graph
construction and shuffle cost more than the work they distribute, and pandas wins
by up to 3.7×. That’s the default, and it’s the right call for most logs. Above
4M, engine="dask" roughly halves the wall-clock, as long as the log is already
on disk in a format Dask reads in parallel, like Parquet or partitioned CSV.
It won’t fix running out of memory on one machine. Dask’s peak memory runs
12 to 25% higher than pandas’ at every size measured. The default scheduler runs
its workers as threads in this same process, so the shuffle buffers and the
finished summary share one address space, and the raw log never being held whole
doesn’t help when the buffers replace it. If pandas runs out of RAM, the fix is
dask.distributed with workers in separate processes, which this library
doesn’t configure for you.
Absolute times are machine-specific; the crossover is the part worth comparing.
Reproduce the table with uv run --extra dask python benchmarks/dask_crossover.py.