Skip to content

Propagate NaN from DataFrame.skew and DataFrame.kurtosis - #12584

Draft
WatchTree-19 wants to merge 1 commit into
dask:mainfrom
WatchTree-19:fix-skew-kurtosis-nan-propagation
Draft

WatchTree-19 wants to merge 1 commit into
dask:mainfrom
WatchTree-19:fix-skew-kurtosis-nan-propagation

Conversation

@WatchTree-19

Copy link
Copy Markdown

skew() and kurtosis() end with

result = m3 / m2**1.5
if result.ndim == 1:
    result = result.fillna(0.0)

result.ndim == 1 is true exactly when the input was a DataFrame, because the reduction of a DataFrame is a per-column Series. A Series input reduces to a 0-d scalar and skips the fillna entirely. So the two paths disagree: for a column holding a single NaN, Series.skew() returns NaN and DataFrame.skew() returns 0.0, and kurtosis returns NaN and -3.0 respectively, from the same data in the same library.

Both docstrings say the method does not filter NaN, and nan_policy defaults to "propagate" and is the only accepted value - "omit" raises NotImplementedError. 0.0 and -3.0 are therefore values the documented API says it will not produce. They are also both inside the plausible range for real data, meaning "symmetric" and "strongly platykurtic", so nothing downstream looks wrong. On a 200k-row frame, one missing value in one column is enough to turn a skew of 6.83 into 0.0 and a kurtosis of 155.8 into -3.0.

dask.array.stats.skew, which the docstring says the implementation follows, and scipy.stats.skew under nan_policy="propagate" both return NaN here.

The existing tests only exercise the Series path, which is the path the fillna skips, so nothing covered this.

Note on constant columns, since a reviewer will ask: for a column of identical values pandas returns 0.0, scipy returns NaN, and dask's Series path returns NaN. This change makes the DataFrame path return NaN, so it agrees with the Series path and with scipy but not with pandas. The NaN-bearing column is the unambiguous case; the constant column is a consistency judgement and I am happy to special-case it if maintainers prefer pandas parity there.

  • Tests added / passed - new test_skew_kurtosis_propagate_nan_on_dataframe passes, and the full dask/dataframe/tests/test_arithmetics_reduction.py suite is green (173 passed, 3 skipped, 4 xfailed)
  • Passes pixi run lint - ruff, black and mypy all clean on both changed files

skew() and kurtosis() end with

    result = m3 / m2**1.5
    if result.ndim == 1:
        result = result.fillna(0.0)

result.ndim == 1 is true exactly when the input was a DataFrame, because the
reduction of a DataFrame is a per-column Series. A Series input reduces to a
0-d scalar and skips the fillna entirely. So the two paths disagree: for a
column holding a single NaN, Series.skew() returns NaN and DataFrame.skew()
returns 0.0, and kurtosis returns NaN and -3.0 respectively, from the same
data in the same library.

Both docstrings say the method does not filter NaN, and nan_policy defaults to
"propagate" and is the only accepted value - "omit" raises NotImplementedError.
0.0 and -3.0 are therefore values the documented API says it will not produce.
They are also both inside the plausible range for real data, meaning "symmetric"
and "strongly platykurtic", so nothing downstream looks wrong. On a 200k-row
frame, one missing value in one column is enough to turn a skew of 6.83 into
0.0 and a kurtosis of 155.8 into -3.0.

dask.array.stats.skew, which the docstring says the implementation follows, and
scipy.stats.skew under nan_policy="propagate" both return NaN here.

The existing tests only exercise the Series path, which is the path the fillna
skips, so nothing covered this.

Note on constant columns, since a reviewer will ask: for a column of identical
values pandas returns 0.0, scipy returns NaN, and dask's Series path returns
NaN. This change makes the DataFrame path return NaN, so it agrees with the
Series path and with scipy but not with pandas. The NaN-bearing column is the
unambiguous case; the constant column is a consistency judgement and I am happy
to special-case it if maintainers prefer pandas parity there.
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Unit Test Results

See test report for an extended history of previous test failures. This is useful for diagnosing flaky tests.

     25 files  ± 0       25 suites  ±0   7h 10m 17s ⏱️ + 18m 17s
 19 915 tests + 1   18 481 ✅ ± 0   1 433 💤 ±0  1 ❌ +1 
379 373 runs  +20  332 102 ✅ +22  47 270 💤  - 3  1 ❌ +1 

For more details on these failures, see this check.

Results for commit 525efed. ± Comparison against base commit 9dc535d.

This branch has not been deployed

No deployments
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.

1 participant