4

我注意到 pandas.DataFrame.describe() 和 numpy.percentile() 处理 NaN 值的方式有所不同。例如

import numpy as np
import pandas as pd

a = pd.DataFrame(np.random.rand(100000),columns=['A'])

>>> a.describe()           
              A
count  100000.000000
mean        0.499713
std         0.288722
min         0.000009
25%         0.249372
50%         0.498889
75%         0.749249
max         0.999991

>>> np.percentile(a,[25,50,75])
[0.24937217017643742, 0.49888913303316823, 0.74924862428575034] # Same as a.describe()

# Add in NaN values
a.ix[1:99999:3] = pd.np.NaN

>>> a.describe()
                  A
count  66667.000000
mean       0.499698
std        0.288825
min        0.000031
25%        0.249285
50%        0.500110
75%        0.750201
max        0.999991

>>> np.percentile(a,[25,50,75])
[0.37341740173545901, 0.75020053461424419, nan] # Not the same as a.describe()

# Remove NaN's
b = a[pd.notnull(a.A)]

>>> np.percentile(b,[25,50,75])
[0.2492848255776256, 0.50010992119477615, 0.75020053461424419] # Now in agreement with describe()

Pandas 在百分位数计算中会忽略 NaN 值,而 numpy 不会。是否有任何令人信服的理由将 NaN 包含在百分位数计算中?看来 Pandas 正确地处理了这个问题,所以我想知道为什么 numpy 不会做出类似的实现。

开始编辑

根据 Jeff 的评论,这在重新采样数据时会成为一个问题。如果我有一个包含 NaN 值的时间序列并且想要重新采样到百分位数(根据这篇文章

upper = df.resample('1A',how=lambda x: np.percentile(x,q=75))

将在计算中包含 NaN 值(就像 numpy 一样)。为避免这种情况,您必须改为放置

upper = tmp.resample('1A',how=lambda x: np.percentile(x[pd.notnull(x.sample_value)],q=75))

也许一个 numpy 请求是有序的。就个人而言,我认为没有任何理由将 NaN 包含在百分位数计算中。在我看来,pd.describe() 和 np.percentile 应该返回完全相同的值(我认为这是预期的行为),但是它们不容易被遗漏的事实(这在文档中没有提到) np.percentile),它可以扭曲统计数据。这是我的担忧。

结束编辑

4

1 回答 1

4

对于您编辑的用例,我想我会留下来pandas使用Series.quantile,而不是np.percentile

>>> df = pd.DataFrame(np.random.rand(100000),columns=['A'], 
...                   index=pd.date_range("Jan 1 2013", freq="H", periods=100000))
>>> df.iloc[1:99999:3] = np.nan
>>> 
>>> upper_np = df.resample('1A',how=lambda x: np.percentile(x,q=75))
>>> upper_np.describe()
        A
count   0
mean  NaN
std   NaN
min   NaN
25%   NaN
50%   NaN
75%   NaN
max   NaN

[8 rows x 1 columns]
>>> upper_pd = df.resample('1A',how=lambda x: x.quantile(0.75))
>>> upper_pd.describe()
               A
count  12.000000
mean    0.745648
std     0.004889
min     0.735160
25%     0.744723
50%     0.747492
75%     0.748965
max     0.750341

[8 rows x 1 columns]
于 2013-12-16T16:15:15.303 回答