Pandas TimeGrouper: .median() 与 .quantile(0.5) 行为不同

4 投票
1 回答
855 浏览
提问于 2025-04-18 18:51

我有一个多年的时间序列数据,想要按季节来找分位数。

从数字上看,这个方法是没问题的。不过,我得到的结果是一个MultiIndexSeries,而我其实想要的是一个单索引的DataFrame

import pandas as pd
import numpy as np

rng = pd.date_range(start='2014-01-01', end='2016-01-01', freq='30T')
a_data = np.random.normal(loc=np.pi, scale=np.e, size=len(rng))
b_data = a_data - 5
df = pd.DataFrame(index=rng, data={'a': a_data, 'b': b_data})    
grouped = df.groupby(pd.TimeGrouper(freq='QS-DEC'))  
mult_idx_series = grouped.quantile(0.5)
mult_idx_series 

这里展示了一个带有MultiIndexSeries

2013-12-01  a    3.079999
            b   -1.920001
2014-03-01  a    3.126490
            b   -1.873510

我原本期待(也希望)得到的输出格式和.median()一样。

median_df = grouped.median()
median_df 

它的样子是这样的:

            a         b
2013-12-01  3.079999 -1.920001
2014-03-01  3.126490 -1.873510

我想指出的是:

  • 其实我并不想要0.5这个分位数
  • 我知道只需要用mult_idx_series.unstack(1)就能得到我想要的格式

我对返回结果的不同形状感到惊讶,想要理解其中的原因。

1 个回答

5

这两者的区别在于,grouped.median() 调用了一个经过优化的(用 Cython 编写的)median 聚合函数,而 grouped.quantile() 则是用一个通用的方式来对每个组应用这个函数。

想象一下:

In [56]: grouped.apply(lambda x: x.quantile(0.5))
Out[56]:
2013-12-01  a    3.175594
            b   -1.824406
2014-03-01  a    3.116556
            b   -1.883444
2014-06-01  a    3.222320
            b   -1.777680
2014-09-01  a    3.207015
            b   -1.792985
2014-12-01  a    3.114767
            b   -1.885233
2015-03-01  a    3.091952
            b   -1.908048
2015-06-01  a    3.220528
            b   -1.779472
2015-09-01  a    3.204990
            b   -1.795010
2015-12-01  a    3.108755
            b   -1.891245
dtype: float64

In [57]: grouped.agg(lambda x: x.quantile(0.5))
Out[57]:
                   a         b
2013-12-01  3.175594 -1.824406
2014-03-01  3.116556 -1.883444
2014-06-01  3.222320 -1.777680
2014-09-01  3.207015 -1.792985
2014-12-01  3.114767 -1.885233
2015-03-01  3.091952 -1.908048
2015-06-01  3.220528 -1.779472
2015-09-01  3.204990 -1.795010
2015-12-01  3.108755 -1.891245

所以 grouped.quantile() 是在做一个通用的 应用,而不是一个 聚合。这样做的原因是,quantile 也可以返回一个数据框(DataFrame),因此并不总是纯粹的聚合。如果你一次计算多个分位数,比如用 grouped.quantile([0.1, 0.5, 0.9])

In [67]: grouped.quantile([0.1, 0.5, 0.9])
Out[67]:
                       a         b
2013-12-01 0.1 -0.310566 -5.310566
           0.5  3.131418 -1.868582
           0.9  6.624399  1.624399
2014-03-01 0.1 -0.219992 -5.219992
           0.5  3.173881 -1.826119
           0.9  6.550259  1.550259
...

撰写回答