diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0aa4b884e..e0023a66b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -60,4 +60,4 @@ There will be automatic checks run on the PR. These include: Please tag maintainers to review. -- @ericmjl +- @ericmjl \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9877dc507..673000340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [ENH] Improve `polars.complete` and `polars.expand`, avoiding the potentially expensive schema computation on lazy frames. @samukweku - [ENH] Add `strip_whitespace` to `clean_names` function. - Issue #1385 +- [FIX] Preserve numeric values in column 0 across `adorn_pct_formatting`, `adorn_ns`, and `adorn_rounding`. - Issue #1676 @sumangouda - [TST] Fix 'HealthCheck' failure in 'test_ecdf_string' by adding missing '@settings' decorator. @mjsr84 - [INF] Automate contributor recognition: weekly workflow discovers new commit authors and regenerates the all-contributors table; backfilled 30 missing contributors. - Issue #1623 diff --git a/janitor/functions/adorn.py b/janitor/functions/adorn.py index 883f26695..e05c532e0 100644 --- a/janitor/functions/adorn.py +++ b/janitor/functions/adorn.py @@ -13,7 +13,7 @@ import pandas as pd import pandas_flavor as pf -from janitor.utils import check +from janitor.utils import check @pf.register_dataframe_method @@ -263,8 +263,8 @@ def adorn_pct_formatting( # Preserve original counts if they exist original_counts = df.attrs.get("_original_counts") - # Identify numeric columns - numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist() + # Select numeric columns starting from the second column (index 1 onwards) + numeric_cols = df.iloc[:, 1:].select_dtypes(include=[np.number]).columns.tolist() rounding_mode = ROUND_HALF_EVEN if rounding == "half to even" else ROUND_HALF_UP quantize_str = f"0.{'0' * digits}" if digits > 0 else "0" @@ -366,8 +366,8 @@ def _default_format_func(n): format_func = _default_format_func - # Get numeric columns from the original counts - numeric_cols = ns.select_dtypes(include=[np.number]).columns.tolist() + # Select numeric columns starting from column index 1 (excluding column 0 identifier) + numeric_cols = ns.iloc[:, 1:].select_dtypes(include=[np.number]).columns.tolist() # Apply to matching columns # Use positional indexing to handle cases where df has more rows than ns @@ -375,6 +375,9 @@ def _default_format_func(n): df_index_list = df.index.tolist() for col in numeric_cols: if col in df.columns: + # Cast column to object dtype so pandas allows string assignment + df[col] = df[col].astype("object") + for i, idx in enumerate(df_index_list): # Only process rows that exist in the original counts if i < len(ns): @@ -390,6 +393,7 @@ def _default_format_func(n): return df + @pf.register_dataframe_method def adorn_title( df: pd.DataFrame, @@ -523,8 +527,8 @@ def adorn_rounding( # Preserve original counts if they exist original_counts = df.attrs.get("_original_counts") - # Identify numeric columns - numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist() + # Identify numeric columns (excluding column 0) + numeric_cols = df.iloc[:, 1:].select_dtypes(include=[np.number]).columns.tolist() rounding_mode = ROUND_HALF_EVEN if rounding == "half to even" else ROUND_HALF_UP quantize_str = f"0.{'0' * digits}" if digits > 0 else "0" diff --git a/mkdocs/devguide.md b/mkdocs/devguide.md index 16760b7fe..18ba99fe9 100644 --- a/mkdocs/devguide.md +++ b/mkdocs/devguide.md @@ -193,6 +193,16 @@ If any checks fail, review the logs and fix the issues. Maintainers may also request changes during code review. Update your branch and push new commits to address feedback. +### Contributor Recognition +pyjanitor uses the @all-contributors bot to recognize all forms of contribution (code, docs, reviews, issues, ideas, etc.). + +When your pull request or issue contribution is merged/completed, a maintainer will add you to the contributors list by commenting: + +```text +@all-contributors please add @your-username for code, docs +``` +You do not need to manually edit any contributor lists! + ## Common Development Tasks All development tasks are available as pixi commands: diff --git a/tests/functions/test_tabyl.py b/tests/functions/test_tabyl.py index f5a13f77d..a766d5819 100644 --- a/tests/functions/test_tabyl.py +++ b/tests/functions/test_tabyl.py @@ -354,3 +354,51 @@ def test_tabyl_preserves_numeric_types_for_adorn(): for col in ["no", "yes"]: if col in pct_result.columns: assert pd.api.types.is_numeric_dtype(pct_result[col]) + +@pytest.mark.functions +def test_adorn_functions_preserve_numeric_first_column(): + """Test that adorn functions preserve numeric values in column 0.""" + df_counts = pd.DataFrame( + { + "cyl": [4, 6, 8], + "gear_3": [1, 2, 1], + "gear_4": [2, 2, 3], + } + ) + + df_pct = pd.DataFrame( + { + "cyl": [4, 6, 8], + "gear_3": ["33.3%", "50.0%", "25.0%"], + "gear_4": ["66.7%", "50.0%", "75.0%"], + } + ) + + df_unrounded = pd.DataFrame( + { + "cyl": [4, 6, 8], + "gear_3": [33.333333, 50.000000, 25.000000], + "gear_4": [66.666667, 50.000000, 75.000000], + } + ) + + # 1. Test adorn_pct_formatting + raw_pct_df = pd.DataFrame( + { + "cyl": [4, 6, 8], + "gear_3": [0.333333, 0.500000, 0.250000], + "gear_4": [0.666667, 0.500000, 0.750000], + } + ) + result_pct = raw_pct_df.adorn_pct_formatting(digits=1) + assert list(result_pct["cyl"]) == [4, 6, 8] + + # 2. Test adorn_ns + result_ns = df_pct.adorn_ns(ns=df_counts) + assert list(result_ns["cyl"]) == [4, 6, 8] + assert result_ns.loc[0, "gear_3"] == "33.3% (1)" + + # 3. Test adorn_rounding + result_rounding = df_unrounded.adorn_rounding(digits=1) + assert list(result_rounding["cyl"]) == [4, 6, 8] + assert result_rounding.loc[0, "gear_3"] == 33.3