Skip to content

Accept pandas DataFrames in Python bindings - #8

Merged
4ment merged 4 commits into
mainfrom
feature/dataframe-bindings
Sep 21, 2026
Merged

4ment merged 4 commits into
mainfrom
feature/dataframe-bindings

Conversation

@4ment

@4ment 4ment commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Read and write every table through the Arrow C Data Interface, and take frames from Python

The store is filled from one decoder, batch_loader, which reads the vendored ArrowSchema/ArrowArray structs from their raw buffers: text in every width and as string views, lists, dates and timestamps, doubles, booleans, integers as text, the null type, and dictionary-encoded columns interned once per used value; sliced arrays and sliced batches are read at their offsets. The parquet loader exports each row group through it, so a file and a frame cannot decode differently, and a table loaded both ways is member-for-member the same store.

Arrow C++ is reduced to parquet_io: a file as a C Data stream and a stream as a file. parquet_io_arrow.cpp is the only file including an Arrow header, and CPPLINK_WITH_ARROW (AUTO, ON, OFF) swaps in a stub that fails with the reason, after which the library and the command line link nothing but the C++ standard library. The merged predictions, clusters, waterfalls and the sample are built by BatchBuilder and handed to the writer as the same structs; gen-sample's output is byte-identical and the 1M load takes the same 1.7 s.

Python takes a pandas frame, a dict of them, a pyarrow table or reader, or a path, all through arrow_c_stream, with object columns sliced on the way in. predict, rescore and cluster return DataFrames, with the reports on last_*; behind each is an ArrowTable exporting borrowed columns, the ids as a dictionary over the store's id arena, zero copy. cluster() reuses the run's rows or resolves a frame or a file through the id index. gen_sample and init work without files. The module built without Arrow installs beside PyPI's pandas and pyarrow 25 and passes the suite; CI gains a no-arrow job.

…ke frames from Python

The store is filled from one decoder, batch_loader, which reads the vendored
ArrowSchema/ArrowArray structs from their raw buffers: text in every width and
as string views, lists, dates and timestamps, doubles, booleans, integers as
text, the null type, and dictionary-encoded columns interned once per used
value; sliced arrays and sliced batches are read at their offsets. The parquet
loader exports each row group through it, so a file and a frame cannot decode
differently, and a table loaded both ways is member-for-member the same store.

Arrow C++ is reduced to parquet_io: a file as a C Data stream and a stream as a
file. parquet_io_arrow.cpp is the only file including an Arrow header, and
CPPLINK_WITH_ARROW (AUTO, ON, OFF) swaps in a stub that fails with the reason,
after which the library and the command line link nothing but the C++ standard
library. The merged predictions, clusters, waterfalls and the sample are built
by BatchBuilder and handed to the writer as the same structs; gen-sample's
output is byte-identical and the 1M load takes the same 1.7 s.

Python takes a pandas frame, a dict of them, a pyarrow table or reader, or a
path, all through __arrow_c_stream__, with object columns sliced on the way in.
predict, rescore and cluster return DataFrames, with the reports on last_*;
behind each is an ArrowTable exporting borrowed columns, the ids as a
dictionary over the store's id arena, zero copy. cluster() reuses the run's
rows or resolves a frame or a file through the id index. gen_sample and init
work without files. The module built without Arrow installs beside PyPI's
pandas and pyarrow 25 and passes the suite; CI gains a no-arrow job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@4ment 4ment linked an issue Sep 21, 2026 that may be closed by this pull request
22 tasks
@4ment
4ment merged commit 3fb8d88 into main Sep 21, 2026
11 checks passed
4ment added a commit that referenced this pull request Sep 28, 2026
Read and write every table through the Arrow C Data Interface, and take frames from Python

The store is filled from one decoder, batch_loader, which reads the vendored
ArrowSchema/ArrowArray structs from their raw buffers: text in every width and
as string views, lists, dates and timestamps, doubles, booleans, integers as
text, the null type, and dictionary-encoded columns interned once per used
value; sliced arrays and sliced batches are read at their offsets. The parquet
loader exports each row group through it, so a file and a frame cannot decode
differently, and a table loaded both ways is member-for-member the same store.

Arrow C++ is reduced to parquet_io: a file as a C Data stream and a stream as a
file. parquet_io_arrow.cpp is the only file including an Arrow header, and
CPPLINK_WITH_ARROW (AUTO, ON, OFF) swaps in a stub that fails with the reason,
after which the library and the command line link nothing but the C++ standard
library. The merged predictions, clusters, waterfalls and the sample are built
by BatchBuilder and handed to the writer as the same structs; gen-sample's
output is byte-identical and the 1M load takes the same 1.7 s.

Python takes a pandas frame, a dict of them, a pyarrow table or reader, or a
path, all through __arrow_c_stream__, with object columns sliced on the way in.
predict, rescore and cluster return DataFrames, with the reports on last_*;
behind each is an ArrowTable exporting borrowed columns, the ids as a
dictionary over the store's id arena, zero copy. cluster() reuses the run's
rows or resolves a frame or a file through the id index. gen_sample and init
work without files. The module built without Arrow installs beside PyPI's
pandas and pyarrow 25 and passes the suite; CI gains a no-arrow job.

* Enhance documentation and examples for parquet support and predictions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accept pandas DataFrames in Python bindings

1 participant