我在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,在这种情况下,根据需要。
然而,当上采样到周期具有非均匀持续时间的频率时,这会给我带来不想要的结果。具有此属性的两种情况:
- 年环比:
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
我想要的是将一年的价值除以几个月,每个月都会收到与其持续时间成比例的分数。即,我希望年份值在几个月内拆分为31/366 * x
、29/366 * x
等:
2020-01 31
2020-02 29
...
2020-11 30
2020-12 31
Freq: M, dtype: float64
有办法做到这一点吗
- 夏令时
第二种情况是在DST转换中,它实际上已经在我的初始示例中显示了。2020-03-29
比我所在时区的其他三月天短1小时,因此它实际上应该比其他日子收到的三月值的一小部分。
尽管这与情况1是同一类问题,但我怀疑它将更难解决。
EDIT:我找到了解决情况1的方法,但没有解决情况2;请看我在这个问题下面的回答。帮助仍然感谢改进我的回答,也包括第二种情况。
如果我们找到一种稳健的方法来做到这一点,并且有点细致,那么我可能会请求它(或者尝试通过pull请求自己添加它(,因为它似乎是一个很好的添加。因此,除了.ffill()
、sum()
、.mean()
等方法之外,扩展PeriodIndexResampler
api以允许具有此功能的.distribute()
方法。
作为部分的答案,为了解决问题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'
(。