用最少的观察次数对 Pandas 重新采样

Posted

技术标签:

【中文标题】用最少的观察次数对 Pandas 重新采样【英文标题】:Resample Pandas With Minimum Required Number of Observations 【发布时间】:2018-08-07 17:22:37 【问题描述】:

我无法弄清楚如何对 pandas 日期时间索引数据帧进行重新采样,但需要最少数量的值才能给出值。我想将每日数据重新采样为每月数据,并要求至少存在 90% 的值才能产生值。

输入每日数据:

import pandas as pd
rng = pd.date_range('1/1/2011', periods=365, freq='D')
ts = pd.Series(pd.np.random.randn(len(rng)), index=rng)
ts['2011-01-01':'2011-01-05']=pd.np.nan #a short length of NANs to timeseries
ts['2011-10-03':'2011-10-30']=pd.np.nan #add ~ month long length of NANs to timeseries

1 月份只有几个 NAN,但 10 月份几乎有整整一个月的 NAN,我想要每月重采样总和的输出:

ts.resample('M').sum()

给出 10 月的 NAN(> 90% 的每日数据丢失)和 1 月的值(

2011-01-31    11.949479
2011-02-28    -1.730698
2011-03-31    -0.141164
2011-04-30    -0.291702
2011-05-31    -1.996223
2011-06-30    -1.936878
2011-07-31     5.025407
2011-08-31    -1.344950
2011-09-30    -2.035502
2011-10-31    -2.571338
2011-11-30   -13.492956
2011-12-31     7.100770

我已阅读 this post,使用滚动平均值和 min_periods;我宁愿继续使用 resample 来直接使用时间索引。这可能吗?我无法在重采样文档或堆栈溢出中找到很多内容来解决这个问题。

【问题讨论】:

This post 说明了 resample 如何能够使用日历月,但带有 min_periods 选项的“滚动”不能。 【参考方案1】:

使用resample 时获取非空值的总和和计数,然后根据需要使用非空计数来更改总和:

# resample getting a sum and non-null count
ts = ts.resample('M').agg(['sum', 'count'])

# determine invalid months
invalid = ts['count'] <= 0.1 * ts.index.days_in_month

# restrict to the sum and null out invalid entries
ts = ts['sum']
ts[invalid] = np.nan

或者,您可以编写一个自定义 sum 函数在内部执行此过滤,尽管它在大型数据集上可能效率不高:

def sum_valid_obs(x):
    min_obs = 0.1 * x.index[0].days_in_month
    valid_obs = x.notnull().sum()
    if valid_obs < min_obs:
        return np.nan
    return x.sum()


ts = ts.resample('M').apply(sum_valid_obs)

任一方法的结果输出:

2011-01-31     3.574859
2011-02-28     2.907705
2011-03-31   -10.060877
2011-04-30     3.270250
2011-05-31    -3.492617
2011-06-30    -1.855461
2011-07-31    -7.363193
2011-08-31     0.128842
2011-09-30    -9.509890
2011-10-31          NaN
2011-11-30     0.543561
2011-12-31     3.354250
Freq: M, Name: sum, dtype: float64

【讨论】:

【参考方案2】:

对于最近的 pandas 版本(从文档中我会说以 v0.22.0 开头),您可以使用 min_count 关键字参数:

import pandas as pd

rng = pd.date_range('1/1/2011', periods=365, freq='D')
ts = pd.Series(pd.np.random.randn(len(rng)), index=rng)
ts['2011-01-01':'2011-01-05'] = pd.np.nan #a short length of NANs to timeseries
ts['2011-10-03':'2011-10-30'] = pd.np.nan #add ~ month long length of NANs to timeseries

ts.resample('M').sum(min_count=20)

输出

2011-01-31     8.000269
2011-02-28    -6.648587
2011-03-31    10.593682
2011-04-30    -1.214945
2011-05-31     4.259289
2011-06-30    -5.986097
2011-07-31    -6.612820
2011-08-31    -1.073952
2011-09-30    -2.164976
2011-10-31          NaN
2011-11-30     1.912070
2011-12-31    12.101526
Freq: M, dtype: float64

【讨论】:

请注意,min_count 参数仅对某些 pandas 重采样方法(如 sum、min、max)有效。在其他方法(如 mean、std)中使用 min_count 参数将引发 UnSupportedFunctionCall。

以上是关于用最少的观察次数对 Pandas 重新采样的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 fill_value 对 Pandas 中的 TimeSeries 重新采样?

猪:如何重新采样时间序列数据?

Pandas:重新采样后计算唯一值

对“ pandas”系列重新采样时每天保持24小时(从每天到每小时)

pandas的resample重采样

Pandas 重新采样倒数的时间序列(或反向重新采样)