【问题标题】:Pandas describe vs scipy.stats percentileofscore with NaN?Pandas 用 NaN 描述 vs scipy.stats percentileofscore?
【发布时间】:2017-04-02 12:49:15
【问题描述】:

我遇到了一种奇怪的情况,我认为 pd.describe 给我的百分位数标记与 scipy.stats percentileofscore 不一致,因为 NaN。

我的 df 是:

      f_recommend
0     3.857143
1     4.500000
2     4.458333
3          NaN
4     3.600000
5          NaN
6     4.285714
7     3.587065
8     4.200000
9          NaN

当我运行df.describe(percentiles=[.25, .5, .75]) 时,我得到:

       f_recommend
count     7.000000
mean      4.069751
std       0.386990
min       3.587065
25%       3.728571
50%       4.200000
75%       4.372024
max       4.500000

当我在移除 NaN 的情况下运行时得到相同的值。

但是,当我想查找特定值时,当我运行 scipy.stats.percentileofscore(df['f_recommend'], 3.61, kind = 'mean') 时,我得到:第 28 个百分位数有 NaN,没有第 20 个百分位数。

有什么想法可以解释这种差异吗?

预计到达时间:

我不认为问题在于我们计算百分位数的方式不同。因为这仅在您以不同方式计算相同 2 个数字的百分位数时才重要。但在这里,describe 给出 25 个百分位数为 3.72。因此,3.61 绝对不可能是第 28 个百分位。没有一个公式应该给出这个。

特别是,当我在没有 NaN 的 6 个值上使用 describe 时,我得到相同的值,所以忽略 NaN,这很好。但是,当我在没有 NaN 的情况下运行分数百分位数时,我得到的数字不匹配。

预计到达时间 2:

更简单的例子:

In [48]: d = pd.DataFrame([1,2,3,4,5,6,7])

In [49]: d.describe()
Out[49]: 
              0
count  7.000000
mean   4.000000
std    2.160247
min    1.000000
25%    2.500000
50%    4.000000
75%    5.500000
max    7.000000

In [50]: sp.stats.percentileofscore(d[0], 2.1, kind = 'mean')
Out[50]: 28.571428571428573

“kind”参数无关紧要,因为 2.1 是独一无二的。

【问题讨论】:

  • 我从来没有深入了解这一点,但我也看到了奇怪的行为,描述返回的平均值甚至不在基础数据的范围内。如果我真的很在意,我通常会直接对 numpy 数组进行操作以确保安全。

标签: python pandas scipy percentile


【解决方案1】:

答案很简单。

没有普遍接受的计算百分位数的公式,特别是当您的数据包含平局或无法在相同大小的存储桶中完美分解时。

例如,查看R 中的文档。有超过七种类型的公式! https://stat.ethz.ch/R-manual/R-devel/library/stats/html/quantile.html

最后,要了解使用了哪个公式,以及差异是否大到足以成为您的问题。

【讨论】:

  • 对,所以我明白为什么 kind = "mean" 是必要的。但这并不能解释为什么 NaN 会受到不同的对待。看来 NaN 被当作 maxint 什么的,这特别令人惊讶。
  • 另外,pandas.describe 似乎并没有说明它做了什么样的百分位计算,这令人困惑。
  • 另外,这仅解释了数字相等的问题。来自描述的第 25 个百分位分数不是 3.61,因此应该是一致的。
  • 兄弟,如果您想确定,只需查看公式即可!祝你好运!
  • 我如何找出描述使用的公式?我可以算出 percentileofscore,因为它有 kind='mean',但描述不太清楚。
【解决方案2】:

scipy.stats.percentileofscore 不会忽略nan,也不会检查值并以某种特殊方式处理它。它只是数据中的另一个浮点值。这意味着 percentileofscore 与包含 nan 的数据的行为是未定义的,因为在比较中 nan 的行为:

In [44]: np.nan > 0
Out[44]: False

In [45]: np.nan < 0
Out[45]: False

In [46]: np.nan == 0
Out[46]: False

In [47]: np.nan == np.nan
Out[47]: False

这些结果都是正确的——这就是nan 的行为方式。但这意味着,为了知道percentileofscore 如何处理nan,您必须知道代码如何进行比较。这是一个你不应该知道的实现细节,你不能依赖它在未来的 scipy 版本中保持不变。

如果您调查percentfileofscore 的行为,您会发现它的行为就像nan 是无限的。例如,如果您将nan 替换为大于输入中任何其他值的值,您将得到相同的结果:

In [53]: percentileofscore([10, 20, 25, 30, np.nan, np.nan], 18)
Out[53]: 16.666666666666664

In [54]: percentileofscore([10, 20, 25, 30, 999, 999], 18)
Out[54]: 16.666666666666664

很遗憾,您不能依赖这种行为。如果将来实现发生变化,nan 最终可能会表现得像负无穷大,或者有其他一些未指定的行为。

这个“问题”的解决方案很简单:不要给percentileofscore 任何nan 值。您必须先清理数据。请注意,这可以很简单:

result = percentileofscore(a[~np.isnan(a)], score)

【讨论】:

  • NAN 实际上是一条红鲱鱼。请参阅我的第二个 1-7 示例。
  • 啊,是的。 percentileofscore([1, 2, 3, 4, 5, 6, 7], score, kind='mean')score 的任何值返回相同的值,其中2 &lt; score &lt; 3。实际上,它是score 的离散函数。没有返回 25.0 的 score 值。 (其他 kind 选项也是如此。)
猜你喜欢
  • 2020-01-06
  • 2019-09-24
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 2020-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多