我有一个带有日期时间索引的大型数据框,需要将数据重新采样到10个相同大小的周期.
到目前为止,我已经尝试找到第一个和最后一个日期来确定数据中的总天数,将其除以10以确定每个期间的大小,然后使用该天数重新采样.例如:
first = df.reset_index().timesubmit.min()
last = df.reset_index().timesubmit.max()
periodsize = str((last-first).days/10) + 'D'
df.resample(periodsize,how='sum')
Run Code Online (Sandbox Code Playgroud)
由于周期大小是向下舍入的int,因此这不能保证重新采样后df中的10个周期.使用浮动在重采样中不起作用.似乎我在这里缺少一些简单的东西,或者我正在解决问题.
import numpy as np
import pandas as pd
n = 10
nrows = 33
index = pd.date_range('2000-1-1', periods=nrows, freq='D')
df = pd.DataFrame(np.ones(nrows), index=index)
print(df)
# 0
# 2000-01-01 1
# 2000-01-02 1
# ...
# 2000-02-01 1
# 2000-02-02 1
first = df.index.min()
last = df.index.max() + pd.Timedelta('1D')
secs = int((last-first).total_seconds()//n)
periodsize = '{:d}S'.format(secs)
result = df.resample(periodsize, how='sum')
print('\n{}'.format(result))
assert len(result) == n
Run Code Online (Sandbox Code Playgroud)
产量
0
2000-01-01 00:00:00 4
2000-01-04 07:12:00 3
2000-01-07 14:24:00 3
2000-01-10 21:36:00 4
2000-01-14 04:48:00 3
2000-01-17 12:00:00 3
2000-01-20 19:12:00 4
2000-01-24 02:24:00 3
2000-01-27 09:36:00 3
2000-01-30 16:48:00 3
Run Code Online (Sandbox Code Playgroud)
- 列中的值0
表示聚合的行数,因为原始 DataFrame 填充了值 1。4 和 3 的模式几乎是均匀的,因为 33 行不能均匀地分为 10 行组。
解释:考虑这个更简单的 DataFrame:
n = 2
nrows = 5
index = pd.date_range('2000-1-1', periods=nrows, freq='D')
df = pd.DataFrame(np.ones(nrows), index=index)
# 0
# 2000-01-01 1
# 2000-01-02 1
# 2000-01-03 1
# 2000-01-04 1
# 2000-01-05 1
Run Code Online (Sandbox Code Playgroud)
使用df.resample('2D', how='sum')
给出了错误的组数
In [366]: df.resample('2D', how='sum')
Out[366]:
0
2000-01-01 2
2000-01-03 2
2000-01-05 1
Run Code Online (Sandbox Code Playgroud)
使用df.resample('3D', how='sum')
给出了正确的组数,但第二组开始时2000-01-04
并没有将 DataFrame 均匀地分成两个等距的组:
In [367]: df.resample('3D', how='sum')
Out[367]:
0
2000-01-01 3
2000-01-04 2
Run Code Online (Sandbox Code Playgroud)
为了做得更好,我们需要以比几天更精细的时间分辨率工作。既然Timedelta
有total_seconds
方法,那我们就分秒必争吧。因此,对于上面的示例,所需的频率字符串将是
In [374]: df.resample('216000S', how='sum')
Out[374]:
0
2000-01-01 00:00:00 3
2000-01-03 12:00:00 2
Run Code Online (Sandbox Code Playgroud)
因为 5 天内有 216000*2 秒:
In [373]: (pd.Timedelta(days=5) / pd.Timedelta('1S'))/2
Out[373]: 216000.0
Run Code Online (Sandbox Code Playgroud)
好的,现在我们需要的是一种概括这一点的方法。我们需要索引中的最小和最大日期:
first = df.index.min()
last = df.index.max() + pd.Timedelta('1D')
Run Code Online (Sandbox Code Playgroud)
我们增加了额外的一天,因为这样可以使天数的差异变得正确。在上面的示例中,2000-01-05 和 2000-01-01 的时间戳之间只有 4 天,
In [377]: (pd.Timestamp('2000-01-05')-pd.Timestamp('2000-01-01')).days
Out[378]: 4
Run Code Online (Sandbox Code Playgroud)
但正如我们在工作示例中看到的,DataFrame 有 5 行代表 5 天。因此,我们需要额外增加一天是有道理的。
现在我们可以计算每个等距组中正确的秒数:
secs = int((last-first).total_seconds()//n)
Run Code Online (Sandbox Code Playgroud)