Skip to main content
 首页 » 编程设计

python之Pandas 按时间分组,指定开始时间

2025年05月04日22www_RR

-- 编辑 我注意到我输入的时间与预期不符。我将中午 12 点以后的时间转换为 24 小时制。不过unutbu的回答应该还是很清楚的。

-- 第二次编辑。我更改了数据以提供更好的示例。

下面是一个按日期索引的时间序列。我想从 start_datetime 开始进行聚合,并根据下面的时间增量(9.5 小时 = 34200 秒)继续聚合。

def main(): 
 
    # start_datetime = datetime.datetime(2013, 1, 1, 8) 
    # end_datetime = datetime.datetime(2013, 1, 1, 5, 30) 
    s = pd.Series( 
        np.arange(2, 10), 
        pd.to_datetime([ 
            '20130101 7:34:04', '20130101 8:34:08', '20130101 10:34:08', 
            '20130101 12:34:15', '20130101 13:34:28', '20130101 12:34:54', 
            '20130101 14:34:55', '20130101 17:29:12'])) 
 
    print(s) 
    bar_size = datetime.timedelta(seconds=60*60*9.5) 
    time_group = pd.Grouper( 
        freq=pd.Timedelta(bar_size), closed='left', label='right') 
    foobar = s.groupby(time_group).agg(np.sum) 
    print(foobar) 
 
if __name__ == "__main__": 
    main() 

运行上面的代码会输出以下内容:

2013-01-01 09:30:00     5 
2013-01-01 19:00:00    39 
Freq: 570T, dtype: int64 

pandas 内部决定从午夜而不是早上 8:00 开始分组。我找不到强制数据框在上午 8:00 开始分组的方法。有人有使用 pandas 函数的解决方案吗?

请您参考如下方法:

使用 base=480 将起点移动 480 分钟(8 小时)。 单位是分钟,因为Grouper频率是570T(这里的T,表示分钟):

import datetime 
import pandas as pd 
 
def main(): 
 
    start_datetime = datetime.datetime(2013, 1, 1, 8) 
    s = pd.Series( 
        range(8), 
        pd.to_datetime([ 
            '20130101 8:34:04', '20130101 10:34:08', '20130101 10:34:08', 
            '20130101 12:34:15', '20130101 1:34:28', '20130101 3:34:54', 
            '20130101 4:34:55', '20130101 5:29:12'])) 
 
    bar_size = datetime.timedelta(seconds=60*60*9.5) 
    time_group = pd.Grouper(freq=bar_size, closed='left', label='right',  
                            base=480) 
    foobar = s.groupby(time_group).agg(sum) 
    print(foobar) 
 
if __name__ == "__main__": 
    main() 

产量

2013-01-01 08:00:00    22 
2013-01-01 17:30:00     6 
Freq: 570T, dtype: int64 

在内部,当 pd.Grouper 被赋予一个频率时,a TimeGrouper is returned :

In [81]: time_group 
Out[81]: <pandas.core.resample.TimeGrouper at 0x7f1499a32198> 

所以传递给pd.Grouper的参数实际上传递给了pd.TimeGrouper。

In [82]: pd.TimeGrouper? 
Init signature: pd.TimeGrouper(self, freq='Min', closed=None, label=None, 
                               how='mean', nperiods=None, axis=0, 
                               fill_method=None, limit=None, loffset=None, 
                               kind=None, convention=None, base=0, **kwargs) 

TimeGrouper 文档没有解释 base 参数,但它与 df.resample 中的含义相同:

In [83]: df.resample? 
Parameters 
---------- 
base : int, default 0 
    For frequencies that evenly subdivide 1 day, the "origin" of the 
    aggregated intervals. For example, for '5min' frequency, base could 
    range from 0 through 4. Defaults to 0