Enhancing CTable, phase 2: pandas engine fix, assign()/col() chaining#676
Merged
Conversation
DataFrame.apply(f, engine=blosc2.jit) returned a raw NumPy array instead of a properly indexed DataFrame/Series when raw=False (the default), since pandas only reconstructs the pandas object itself for raw=True. Series.map(f, engine=blosc2.jit) now works instead of always raising NotImplementedError. Non-numeric columns raise a clear ValueError instead of a deep numexpr error. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
col(name) builds a deferred column expression that replays operators against a table's columns only once bound (assign(), indexing, where()), reusing all existing Column/NullableExpr null-propagation and comparison semantics rather than a second expression engine. assign() returns a view with additional computed columns without mutating the table or copying column data. Also fixes a pre-existing bug found while testing the chain end-to-end: CTable.head()/tail() ignored _cached_live_positions and silently returned rows in physical order instead of sorted order after a lazily-sorted view. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Built and benchmarked the segmented reduceat-based UDF aggregation path specified for P4 (1e6 rows, 100k groups, a.max()-a.min()). Measured 1.2x against the plan's own >=5x gate (checked at other scales too: 1.1x-1.4x, never close), root-caused via cProfile to per-chunk-per-group Python bookkeeping in _merge_partials/_compute_partials that both the loop and segmented paths pay identically and that segmentation cannot skip. Per the plan's own benchmark-gate rule, the dispatch is not merged; the code was reverted rather than left in disabled. Kept the one fix worth keeping on its own merits: a @blosc2.dsl_kernel- decorated function passed as a groupby UDF aggregation crashed unconditionally (DSLKernel.__call__ uses a different calling convention than this call site expects) -- now unwrapped to the plain function. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Demonstrates engine=blosc2.jit for DataFrame.apply/Series.map, including the axis=0 speedup (measured, not just asserted) and the honest axis=1 result (no speedup, typically slower), plus the clear error for non-numeric columns. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
axis=1 is slower with the engine (already noted in the code comment); showing timings for it added noise without a point. Also fixes column alignment in the axis=0 timing output. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Demonstrates the pandas-3 style chain, col() reuse across tables, null propagation, assign() on a view plus its read-only/no-copy guarantees, and the two documented error cases (unknown column at bind time, no method calls unbound). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ase-3 plan - Add CTable.assign and blosc2.col to the API reference, with a short chained-pipelines section. - Fix the assign() docstring: values are bound against self, not the view. - Make the pandas major-version test guard numeric instead of a string comparison. - Close the phase-2 plan and carry deferred P3/P5 forward into plans/enhancing-ctable-phase3.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lands phase 2 of the CTable enhancement work (plan:
plans/enhancing-ctable-phase2.md). The remaining items (first-class variable-length strings, mask-based nullable columns) are deferred toplans/enhancing-ctable-phase3.md, included here.New features
CTable.assign(**named_exprs): returns a view with additional computed columns — never mutates the table, never copies column data. Accepts the same forms asadd_computed_column, plusColumn/NullableExprand the new unbound expressions.blosc2.col(name): unbound column expression. Defers operator replay until bound to a table (assign(),t[...],where()), reusing the existingColumn/NullableExproperator machinery so null propagation and comparison semantics are identical to the bound form. Enables the pandas-3 headline idiom:Bug fixes
engine=blosc2.jitvs pandas 3.0.3: with the defaultraw=False,DataFrame.applyreturned a raw ndarray instead of a properly indexedDataFrame/Series. Now reconstructs the pandas object, mirroring pandas' ownraw=Truepath.Series.map(f, engine=blosc2.jit)is now implemented; non-numeric columns raise a clearValueErrorinstead of a deep numexpr error.CTable.head()/tail()on lazily-sorted views silently discarded sort order (they ignored_cached_live_positions);t.where(...).sort_by(...).head(10)came back in physical order. Pre-existing bug, found while testing the chain above.@blosc2.dsl_kernel-decorated groupby UDF aggregations crashed unconditionally (calling-convention mismatch); the wrapped plain function is now used.Explicitly not merged
The plan's P4 (segmented
reduceatacceleration fordsl_kernelgroupby UDFs) was built, verified correct, and rejected by its own benchmark gate: 1.2x measured vs the required ≥5x — the groupby pipeline's partial-merging bookkeeping dominates, not the per-group UDF calls. Details in the plan's P4 implementation notes; only its crash fix (above) was kept.Docs / examples / benchmarks
bench/bench_pandas_engine.pyandexamples/pandas_engine.py.examples/ctable/assign_col.pyandexamples/ctable/treestore_bundle.py.CTable.assign/blosc2.coladded to the API reference with a chained-pipelines section.Testing
tests/ctable(1332 tests) andtests/test_pandas_udf_engine.pyall green, including new end-to-end tests through real pandas 3.0.3 and 11 new tests forcol()/assign().🤖 Generated with Claude Code