From 518cf6eaf0b5093bcfab235167929b55acaa310d Mon Sep 17 00:00:00 2001 From: Eric Hills <53243273+ebhills@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:10:00 -0500 Subject: [PATCH 1/3] Add value counts aggregation to select.group_by --- tests/recipes/wrangles/test_select.py | 21 +++++++++++++++++++++ wrangles/recipe_wrangles/select.py | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/tests/recipes/wrangles/test_select.py b/tests/recipes/wrangles/test_select.py index 813d3f679..834f948f5 100644 --- a/tests/recipes/wrangles/test_select.py +++ b/tests/recipes/wrangles/test_select.py @@ -1940,6 +1940,27 @@ def test_group_by_to_list_multiple_list(self): list(df.values[1]) == ['b', [4], [8]] ) + def test_group_by_value_counts_as_json_safe_dictionary(self): + df = wrangles.recipe.run( + """ + wrangles: + - select.group_by: + counts: + - Selection: Selection Counts + - Review: Review Counts + auto_rename_columns: false + """, + dataframe=pd.DataFrame({ + "Selection": ["Primary", "Primary", "None"], + "Review": [False, False, True], + }), + ) + + assert df.to_dict(orient="records") == [{ + "Selection Counts": {"Primary": 2, "None": 1}, + "Review Counts": {"false": 2, "true": 1}, + }] + def test_group_by_where(self): """ diff --git a/wrangles/recipe_wrangles/select.py b/wrangles/recipe_wrangles/select.py index d170e83ca..7acf2054c 100644 --- a/wrangles/recipe_wrangles/select.py +++ b/wrangles/recipe_wrangles/select.py @@ -318,6 +318,13 @@ def group_by( - string - array description: The count of values for these column(s) + counts: + type: + - string + - array + description: >- + Return a dictionary containing the count of each distinct value for + these column(s). Keys are converted to JSON-safe strings. std: type: - string @@ -399,6 +406,20 @@ def percentile_(x): # Add option to group as a list elif operation == "list": operation = list + elif operation == "counts": + def counts(values): + output = {} + for value, count in values.value_counts(dropna=False).items(): + if _pd.isna(value): + key = "null" + elif isinstance(value, bool): + key = str(value).lower() + else: + key = str(value) + output[key] = int(count) + return output + counts.__name__ = "counts" + operation = counts if not isinstance(columns, list): columns = [columns] for column in columns: From f85253101ec897852b6e899d4bbe013fa71be5a9 Mon Sep 17 00:00:00 2001 From: Eric Hills <53243273+ebhills@users.noreply.github.com> Date: Fri, 14 Aug 2026 15:03:02 -0500 Subject: [PATCH 2/3] Add null values to test case Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/recipes/wrangles/test_select.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/recipes/wrangles/test_select.py b/tests/recipes/wrangles/test_select.py index 834f948f5..dcf2f1a29 100644 --- a/tests/recipes/wrangles/test_select.py +++ b/tests/recipes/wrangles/test_select.py @@ -1951,14 +1951,14 @@ def test_group_by_value_counts_as_json_safe_dictionary(self): auto_rename_columns: false """, dataframe=pd.DataFrame({ - "Selection": ["Primary", "Primary", "None"], - "Review": [False, False, True], + "Selection": ["Primary", "Primary", "None", None], + "Review": [False, False, True, None], }), ) assert df.to_dict(orient="records") == [{ - "Selection Counts": {"Primary": 2, "None": 1}, - "Review Counts": {"false": 2, "true": 1}, + "Selection Counts": {"Primary": 2, "None": 1, "null": 1}, + "Review Counts": {"false": 2, "true": 1, "null": 1}, }] From ae8a5c2c48d21e5d1529b9609d24d0a5cbfdb105 Mon Sep 17 00:00:00 2001 From: Eric Hills <53243273+ebhills@users.noreply.github.com> Date: Fri, 14 Aug 2026 15:04:07 -0500 Subject: [PATCH 3/3] Document null and bool behavior in schema Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- wrangles/recipe_wrangles/select.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrangles/recipe_wrangles/select.py b/wrangles/recipe_wrangles/select.py index 7acf2054c..dc4f18377 100644 --- a/wrangles/recipe_wrangles/select.py +++ b/wrangles/recipe_wrangles/select.py @@ -324,7 +324,8 @@ def group_by( - array description: >- Return a dictionary containing the count of each distinct value for - these column(s). Keys are converted to JSON-safe strings. + these column(s). Keys are converted to JSON-safe strings; missing + values use the key "null" and booleans use lowercase "true"/"false". std: type: - string