2

我在 python 中有一个函数,用于在上采样时分配值。例如,要对我的汽车从每月到每天的行驶距离进行上采样:

def distribute(df, freq:str):
    # if there's an easier way please do comment
    df_new = df.resample(freq).asfreq().fillna(0)
    return df_new.groupby(pd.Grouper(freq=df.index.freq)).transform(np.mean)

import pandas as pd
import numpy as np
distances = pd.Series([300, 300], pd.period_range('2020-02', freq='M', periods=2))
distribute(distances, 'D')
2020-02-01    10.344828
2020-02-02    10.344828
2020-02-03    10.344828
2020-02-04    10.344828
...                 ...
2020-03-28     9.677419
2020-03-29     9.677419
2020-03-30     9.677419
2020-03-31     9.677419
Freq: D, dtype: float64

该函数将每个月的值平均除以该月的天数,这会导致该2020-02值除以 29,2020-03在这种情况下,根据需要将该值除以 31。


但是,当上采样到周期具有不均匀持续时间的频率时,这会给我带来不想要的结果。此属性的两种情况:

  1. 逐月:
distances2 = pd.Series([366], pd.PeriodIndex(['2020'], freq='Y'))
distribute(distances2, 'M')
2020-01    30.5
2020-02    30.5
...         ...
2020-11    30.5
2020-12    30.5
Freq: M, dtype: float64

想要的是将一年的价值划分为几个月,每个月都会收到与其 duration 成比例的分数。31/366 * x即,我希望将年份值拆分为,29/366 * x等月份:

2020-01    31
2020-02    29
           ...
2020-11    30
2020-12    31
Freq: M, dtype: float64

有没有办法做到这一点?

  1. 夏令时

第二种情况是在 DST 转换中,它实际上已经在我的初始示例中显示。2020-03-29比我的时区中的其他三月天短 1 小时,因此它实际上应该比其他天收到更小的三月值。

尽管它与情况 1 是同一类型的问题,但我怀疑它会更难解决。


编辑:我找到了解决情况 1 的方法,但不是情况 2;在这个问题下面看到我的答案。在改进我的答案以及包括第二种情况方面仍然感谢帮助。


如果我们找到了一种稳健的方法来做这件事,但它有点详细,我可能是一个很好的请求功能(或者尝试通过拉取请求自己添加它),因为它似乎是一个很好的补充。因此,扩展PeriodIndexResamplerapi 以允许.distribute()具有此功能的方法,除了.ffill(),sum().mean()方法。

4

1 回答 1

0

作为部分答案,为了解决问题 1,我发现我可以首先上采样到具有统一持续时间的更高频率周期,例如“D”,然后再下采样到所需频率:

def distribute(df, freq:str):
    # now it's really wild
    df_D = df.resample('D').asfreq().fillna(0)
    df_D_spread = df_D.groupby(pd.Grouper(freq=df.index.freq)).transform(np.mean)
    return df_D_spread.groupby(pd.Grouper(freq=freq)).sum()

distances2 = pd.Series([366], pd.PeriodIndex(['2020'], freq='Y'))
distribute(distances2, 'M')
2020-01    31.0
2020-02    29.0
...         ...
2020-11    30.0
2020-12    31.0
Freq: M, dtype: float64

然而/备注:

  • 它非常复杂且难以阅读。而且还浪费内存空间,将一年扩展到 366 或 365 行。一定会有更好的办法?

  • 它没有解决第二个问题。
    事实上,我之所以选择'D'不是,是'H'因为句点不支持时区。实际上,并非所有的日子都是相同的长度,每当我们找到一种方法来包含这一事实时,我们可能需要更改代码以进行上采样'H'(甚至'15T'对于分数时区)。

于 2020-07-24T10:01:15.810 回答