pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理

Posted

技术标签:

【中文标题】pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理【英文标题】:pandas.DataFrame.describe() vs numpy.percentile() NaN handling 【发布时间】:2014-01-04 01:22:21 【问题描述】:

我注意到 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 值的时间序列并且想要重新采样到百分位数(每 this post)

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),它可以扭曲统计数据。这是我的担心。

结束编辑

【问题讨论】:

你当然可以向 numpy 提出功能请求;他们有专门的 nan 处理方法,例如nanmean,nansum,所以我怀疑这是必要的。改用熊猫! 这些天我更喜欢熊猫。但是,这在重新采样数据时成为一个问题,例如见上面的编辑。 nan 处理将以性能为代价进行。 np.percentile(a[~np.isnan(a)], [25,50,75]) 【参考方案1】:

对于您编辑的用例,我想我会留在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]

【讨论】:

以上是关于pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理的主要内容,如果未能解决你的问题,请参考以下文章

pandas.DataFrame.describe() 在 .py 脚本中没有输出

pandas.DataFrame.describe 官方文档翻译percentile_width,percentiles,include, exclude

对 Pandas DataFrame Describe 输出进行排序(早期解决方案不起作用)

一些Pandas常用方法