Repository navigation
Releases
v0.3.0
What's Changed
- Map the file for a parallel CSV read by @randyzwitch in #144
- Take signed decimals on the one-pass Float64 parser by @randyzwitch in #145
- Pipeline CSV decoding and reduce parsing and assembly overhead by @randyzwitch in #153
- Avoid reparsing wide decimal floats in CSV and casts by @randyzwitch in #154
- Accelerate numeric reductions, ordered joins, and decimal parsing by @randyzwitch in #155
- CSV: translate Polars atoi_simd integer parsing by @randyzwitch in #159
- Replace public CSV reader with the Polars-derived pipeline by @randyzwitch in #161
- Avoid owned strings in numeric casts and measure the path by @randyzwitch in #162
- Append single CSV chunks directly during assembly by @randyzwitch in #163
- Stop rechunking fused CSV expressions on every batch by @randyzwitch in #164
- Move benchmark research to wiki and remove third_party directory by @randyzwitch in #166
- Filter large chunked frames without input rechunking by @randyzwitch in #167
- Keep CSV source attribution in central notice by @randyzwitch in #168
- Keep moderately repeated grouping keys on serial route by @randyzwitch in #169
- Encode chunked string group keys without rechunking by @randyzwitch in #170
- Gather serial group keys from source chunks by @randyzwitch in #171
- Assemble parallel string gathers as chunks by @randyzwitch in #172
- Gather medium multicolumn frames by column by @randyzwitch in #173
- Gather partitioned group inputs in one pass by @randyzwitch in #174
- Share left columns for identity-order join output by @randyzwitch in #175
- Rechunk parallel gather inputs by column by @randyzwitch in #176
- Count grouped bare columns without row batches by @randyzwitch in #177
- Accumulate Float64 reductions eight values at a time by @randyzwitch in #178
- Keep CSV integer source history out of code comments by @randyzwitch in #179
- Size CSV decode workers to mapped input by @randyzwitch in #180
- Scan chunked Float64 sums without materializing chunk views by @randyzwitch in #181
- Sort medium low-cardinality first keys by independent buckets by @randyzwitch in #182
- Pack fused expression validity by byte by @randyzwitch in #184
- Use constant-size hash storage for group cardinality sampling by @randyzwitch in #186
- Reuse hash worker histograms for group scatter by @randyzwitch in #187
- Encode single string group keys in parallel by @randyzwitch in #189
- Select simple Float64 filter rows directly by @randyzwitch in #183
- Use direct row lookup for dense ascending Int64 right joins by @randyzwitch in #190
- Evaluate large fused expressions on source chunk windows by @randyzwitch in #185
- Keep parallel expression outputs chunked by @randyzwitch in #188
- Split large sorted chunk gathers across workers by @randyzwitch in #191
- Speed up low-cardinality Int64 grouping with direct key lookup by @randyzwitch in #192
- Reduce filter row-index concatenation allocations by @randyzwitch in #193
- Use standard sort for parallel index runs by @randyzwitch in #194
- Inline hot CSV field splitting path by @randyzwitch in #195
- Filter aligned chunks directly with bounded workers by @randyzwitch in #196
- Keep radix sort keys local to low-cardinality buckets by @randyzwitch in #197
- Avoid partition gather for skewed small-domain groups by @randyzwitch in #198
- Parse short CSV integers with scalar digits by @randyzwitch in #199
- Preallocate row evaluation outputs by @randyzwitch in #201
- Skip redundant bounds checks in short CSV integers by @randyzwitch in #203
- Scan plain CSV records with one delimiter vector by @randyzwitch in #204
- perf: write fused comparison results directly to bitmap by @randyzwitch in #205
- Aggregate numeric sum and count directly by hash bucket by @randyzwitch in #200
- perf: preserve absent validity in all-valid column gathers by @randyzwitch in #206
- Scale CSV chunk count with input size by @randyzwitch in #207
- Evaluate expressions in eight-row SIMD batches by @randyzwitch in #208
- Use larger bounded batches for with_columns by @randyzwitch in #209
- Decode CSV columns in bounded row groups by @randyzwitch in #210
- Skip validity work for all-valid parallel gathers by @randyzwitch in #211
- Fuse low-cardinality grouped sum and count across workers by @randyzwitch in #212
- Pipeline lazy CSV filters through decode workers by @randyzwitch in #213
- Fuse bounded grouped Float64 aggregates across worker ranges by @randyzwitch in #214
- Defer sort gathers and push row-local filters below sort by @randyzwitch in #215
- Benchmark general joins against Polars at large row counts by @randyzwitch in #216
- Use direct membership for bounded Int64 semi and anti joins by @randyzwitch in #230
- Parallelize membership probes and select join rows by chunk by @randyzwitch in #231
- Parallelize right joins and avoid unused row index by @randyzwitch in #233
- Index high-cardinality joins by original right rows by @randyzwitch in #234
- Pack join hash entries and specialize Int64 probes by @randyzwitch in #235
- Consolidate related tests into fewer CI modules by @randyzwitch in #243
- Index regular Int64 join domains by compact stride by @randyzwitch in #244
- Skip row-chain traversal for unique bounded join keys by @randyzwitch in #245
- Build large bounded join indexes across key ranges by @randyzwitch in #246
- Gather ordered repeated join rows within source chunks by @randyzwitch in #247
- Compare contiguous string join keys by bytes by @randyzwitch in #248
- Use interval membership for consecutive Int64 join keys by @randyzwitch in #249
- Map ordered strided Int64 join keys directly to rows by @randyzwitch in #250
- Use bounded strided index for smaller right joins by @randyzwitch in #251
- Map repeated ordered join keys directly to row runs by @randyzwitch in #252
- Use open addressing for high-cardinality join indexes by @randyzwitch in #253
- Fuse bounded membership with aligned chunk filtering by @randyzwitch in #254
- Avoid source validity checks in null-extended gathers by @randyzwitch in https://github.com/randyzwitch/dataframe_m...
v0.2.0
v0.2.0 — Mojo 1.2 only Drops Mojo 1.1: a compiled Mojo package loads only in the version that produced it, so consumers on 1.1 stay on v0.1.3. Built and tested against 1.2.0.dev2026092105. Since v0.1.3: row-encoded sort keys for fixed-width and string columns (#108), the scoped worker pool (#103), parallel join output and partitioned id assembly (#105), and the CSV field-slice decode, bulk byte copy, UTF-8 narrowing and parallel concat (#107). Against Polars at 1M rows over that span: sort 6.7x -> 1.7x, join 6.8x -> 4.7x, CSV read 7.8x -> 5.2x.
v0.1.3
Parallel grouping, join and sort, plus two timestamp fixes that matter more than any of the speedups for common data.
[workspace]
preview = ["pixi-build"]
[dependencies]
mojo = ">=1.1.0,<1.2"
dataframe_mojo = { git = "https://github.com/randyzwitch/dataframe_mojo.git", tag = "v0.1.3" }Fixed
- Datetimes accept an ISO 8601 zone designator: a trailing
Zmeans UTC, and+HH:MM,-HH:MM,+HHMMand+HHconvert to UTC. Both previously raised, which rejected the most common datetime spelling in real data (#107). - Format directives with no separator between them take their exact width, so
%Y%m%dreads20240228instead of letting%Yconsume six digits and fail (#107).
Changed
At 1,000,000 rows on a 32-core Threadripper, against v0.1.2:
| workload | v0.1.2 | v0.1.3 |
|---|---|---|
| grouping, ~100k groups | 51.7 ms | 24.5 ms |
| join, inner | 283 ms | 179 ms |
| sort, two keys | 594 ms | 345 ms |
| CSV read | 1,260 ms | 1,081 ms |
- Grouping partitions rows by key hash so no dictionaries or reduction states are ever merged, which is what made earlier attempts lose at high cardinality (#104).
- Joins encode both sides' keys one hash bucket at a time instead of building one dictionary over everything (#105).
sort,arg_sort,top_kandbottom_ksort one row range per worker and merge the runs, in the same stable order as before for any worker count (#108).- CSV parses plain decimal floats in one exact pass rather than validating and then re-parsing (#107).
Added
pixi run -e oracle bench-polars: a head-to-head benchmark against Polars on identical inputs with thread counts pinned equal, which produced every number above (#102).
Targets Mojo 1.1. A compiled Mojo package only loads in the Mojo version that produced it, and pixi builds a source dependency with the newest Mojo that [package.host-dependencies] allows rather than the consumer's pin, so each tag targets one Mojo version.
v0.1.2
Adds the two APIs another package needs to read data out of a frame efficiently.
[workspace]
preview = ["pixi-build"]
[dependencies]
mojo = ">=1.1.0,<1.2"
dataframe_mojo = { git = "https://github.com/randyzwitch/dataframe_mojo.git", tag = "v0.1.2" }Arrow buffer access (#91)
unsafe_values(), unsafe_validity() / validity_offset(), unsafe_bytes() / unsafe_offsets() for large_utf8, a non-raising is_valid(i), and to_list(). A consumer reads values in place instead of one tagged AnyValue per element: summing a million-row Float64 column drops from about 3,500 us to about 700 us.
The values pointer is shifted to the window's row 0; the validity bitmap is not, so bit validity_offset() + i describes row i. Null slots hold whatever the buffer holds, as in Arrow, where they are undefined. Nothing converts dtypes.
Row-index grouping (#92)
DataFrame.group_indices(keys) gives the grouping without the aggregation: ids, rows(g), all_rows, sizes, count, and representative(g) for where a group's key values live. Building sub-frames is left to the caller, who may prefer to index the shared buffers directly.
The two compose: hold row indices per group and read values straight from the buffers, without materializing a sub-frame per group.
Targets Mojo 1.1. A compiled Mojo package only loads in the Mojo version that produced it, and pixi builds a source dependency with the newest Mojo that [package.host-dependencies] allows rather than the consumer's pin, so each tag targets one Mojo version.
v0.1.1
The first tag carrying the complete feature set. Prefer this over v0.1.0, which was tagged before bit-packed Boolean columns were known to be missing from main.
[workspace]
preview = ["pixi-build"]
[dependencies]
mojo = ">=1.1.0,<1.2"
dataframe_mojo = { git = "https://github.com/randyzwitch/dataframe_mojo.git", tag = "v0.1.1" }from dataframe import DataFrame, Series, Column, colTargets Mojo 1.1. A compiled Mojo package only loads in the Mojo version that produced it, and pixi builds a source dependency with the newest Mojo that [package.host-dependencies] allows rather than the consumer's pin, so each tag targets one Mojo version.
See CHANGELOG.md for the feature set. The API is pre-1.0 and provisional.
v0.1.0
First tagged release, and the first that another Pixi workspace can depend on.
[workspace]
preview = ["pixi-build"]
[dependencies]
mojo = ">=1.1.0,<1.2"
dataframe_mojo = { git = "https://github.com/randyzwitch/dataframe_mojo.git", tag = "v0.1.0" }from dataframe import DataFrame, Series, Column, colTargets Mojo 1.1. A compiled Mojo package only loads in the Mojo version that produced it, and pixi builds a source dependency with the newest Mojo that [package.host-dependencies] allows rather than the consumer's pin, so each tag targets one Mojo version.
See CHANGELOG.md for what the library does. The API is pre-1.0 and provisional.