Recognize named-aggregation lambdas as scans in GroupBy - #23300
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughChangesGroupby scan lambda handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
python/cudf/cudf/core/groupby/groupby.py (1)
218-239: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winCache resolved callable names before computing both predicates.
get_nameexecutes the callable probe, but_is_all_scan_aggregatecalls it separately inall()andany(). Materialize the flattened resolved names once, then derive both predicates from that list; ideally reuse the aggregation resolution already performed bymake_aggregation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@python/cudf/cudf/core/groupby/groupby.py` around lines 218 - 239, Update the groupby aggregation-name resolution around get_name and _is_all_scan_aggregate to materialize each flattened callable’s resolved name once, then compute both all-scan and any-scan predicates from that cached list. Reuse the names produced during make_aggregation when available, avoiding repeated callable probes while preserving existing handling for non-callables and true UDFs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@python/cudf/cudf/tests/groupby/test_transform.py`:
- Around line 82-91: Expand test_transform_scan_lambda to parameterize both
cumsum and cumprod across empty, all-null, single-element, and mixed-type
inputs, while retaining expected pandas-versus-cuDF comparisons for each case.
Add the repository-required unit benchmark covering this scan-lambda regression.
---
Nitpick comments:
In `@python/cudf/cudf/core/groupby/groupby.py`:
- Around line 218-239: Update the groupby aggregation-name resolution around
get_name and _is_all_scan_aggregate to materialize each flattened callable’s
resolved name once, then compute both all-scan and any-scan predicates from that
cached list. Reuse the names produced during make_aggregation when available,
avoiding repeated callable probes while preserving existing handling for
non-callables and true UDFs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 6c499992-a1df-4636-84be-e14d105a6a93
📒 Files selected for processing (3)
python/cudf/cudf/core/groupby/groupby.pypython/cudf/cudf/pandas/scripts/pandas-testing-plugin.pypython/cudf/cudf/tests/groupby/test_transform.py
💤 Files with no reviewable changes (1)
- python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
| def test_transform_scan_lambda(): | ||
| # a named-aggregation lambda resolving to a scan must scan per group, | ||
| # not broadcast the group total | ||
| pdf = pd.DataFrame({"key": [0, 0, 1, 1], "val": [1.0, 2.0, 3.0, 4.0]}) | ||
| gdf = cudf.DataFrame(pdf) | ||
|
|
||
| expect = pdf.groupby("key")["val"].transform(lambda x: x.cumsum()) | ||
| got = gdf.groupby("key")["val"].transform(lambda x: x.cumsum()) | ||
|
|
||
| assert_eq(expect, got) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Expand scan-lambda regression coverage.
This test covers only cumsum on a simple non-null float input. Parameterize the regression for cumsum and cumprod, and add empty, all-null, single-element, and mixed-type cases. Add a unit benchmark for this bug fix as required by the repository guidelines.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@python/cudf/cudf/tests/groupby/test_transform.py` around lines 82 - 91,
Expand test_transform_scan_lambda to parameterize both cumsum and cumprod across
empty, all-null, single-element, and mixed-type inputs, while retaining expected
pandas-versus-cuDF comparisons for each case. Add the repository-required unit
benchmark covering this scan-lambda regression.
Source: Coding guidelines
A lambda like ``lambda x: x.cumsum()`` resolves through
make_aggregation's op(Aggregation) protocol, where Aggregation.cumsum
is an alias of sum: the scan/reduction distinction exists only in the
aggregation name. _is_all_scan_aggregate identified scans via
``__name__`` ("<lambda>"), so such transforms silently computed group
totals and broadcast them instead of scanning. Probe callables with a
name-recording stand-in mirroring the op(Aggregation) protocol; true
UDFs raise inside the probe and fall back to ``__name__`` as before.
42efad0 to
ac77cac
Compare
|
/okay to test 76649b0 |
|
/okay to test 126a93e |
|
/okay to test d1e8eb3 |
vyasr
left a comment
There was a problem hiding this comment.
Wow this is a convoluted fix :( I really wish we didn't have to support agg machinery through callables the way that we do.
…mbda-scan-detection # Conflicts: # python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
|
/okay to test e514d19 |
…mbda-scan-detection # Conflicts: # python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py # python/cudf/cudf/tests/groupby/test_transform.py
|
/okay to test 259812d |
|
/merge |
A lambda like `lambda x: x.cumsum()` resolves through `make_aggregation`'s `op(Aggregation)` protocol, where `Aggregation.cumsum` is an alias of `sum`: the scan/reduction distinction exists only in the aggregation name. `_is_all_scan_aggregate` identified scans via `__name__` (`"<lambda>"`), so such transforms silently computed group totals and broadcast them instead of scanning. Probe callables with a name-recording stand-in mirroring the `op(Aggregation)` protocol; true UDFs raise inside the probe and fall back to `__name__` as before. Fixes 2 pandas-tests (`test_cython_transform_series[cumsum/cumprod-<lambda>]`); their xfail entries are removed. Authors: - GALI PREM SAGAR (https://github.com/galipremsagar) Approvers: - Vyas Ramasubramani (https://github.com/vyasr) URL: NVIDIA#23300
Description
A lambda like
lambda x: x.cumsum()resolves throughmake_aggregation'sop(Aggregation)protocol, whereAggregation.cumsumis an alias ofsum: the scan/reduction distinction exists only in the aggregation name._is_all_scan_aggregateidentified scans via__name__("<lambda>"), so such transforms silently computed group totals and broadcast them instead of scanning. Probe callables with a name-recording stand-in mirroring theop(Aggregation)protocol; true UDFs raise inside the probe and fall back to__name__as before.Fixes 2 pandas-tests (
test_cython_transform_series[cumsum/cumprod-<lambda>]); their xfail entries are removed.Checklist