You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义季度起始日期的Pandas DataFrame分组求和方案问询

自定义起始日期的季度分组求和方案

需求说明

我有一个包含网站日访问量(DailyViews)和日使用时长(DailyMinutes)的Pandas DataFrame,需要按季度分组求和,但有两个特殊要求:

  • 季度起始为非标准日期(例如Q1为2月27日至5月26日)
  • 支持指定任意月日作为季度起始,适配不同网站跨度较大的日期范围

数据复现代码

import random
import pandas as pd

date_range = pd.date_range(start='2018-1-1', end='2022-10-03')
daily_views = [random.randint(1000,9999) for i in range(len(date_range))]
daily_minutes = [random.randint(1000,9999) for i in range(len(date_range))]

df = pd.DataFrame(
    {'DailyViews': daily_views, 'DailyMinutes': daily_minutes},
    index=date_range,
)

尝试过的无效方法

  1. 使用df_grouped = df.groupby(df.index.shift(freq='Q')).sum():无法实现精细的季度偏移控制
  2. 使用df_resampled = df.resample('Q', convention='end', offset=datetime.timedelta(days=25)).sum():修改offset后未达到预期效果

当前手动用apply()逐行判断的方法效率极低,还有一个仅支持整月调整的临时方案,但无法处理精确到日的起始,且生成的季度字符串转datetime会被识别为标准季度。

高效解决方案

方法1:自定义函数生成季度标签(简洁易用)

通过日期计算确定每个日期所属的自定义季度,避免逐行循环:

import numpy as np

def get_custom_quarter(dt, start_month=2, start_day=27):
    # 生成当前年份的季度起始日期
    start_date = pd.Timestamp(year=dt.year, month=start_month, day=start_day)
    # 若当前日期早于当年起始日,用上一年的起始日作为基准
    if dt < start_date:
        start_date = start_date - pd.DateOffset(years=1)
    # 计算与基准日的天数差,每91天划分为一个季度(近似自然季度长度)
    days_diff = (dt - start_date).days
    quarter_num = (days_diff // 91) + 1
    # 确定季度所属年份
    quarter_year = start_date.year + (days_diff // 365)
    return f"{quarter_year}Q{quarter_num}"

# 生成自定义季度标签
df['CustomQuarter'] = df.index.map(lambda x: get_custom_quarter(x, start_month=2, start_day=27))
# 按自定义季度分组求和
df_grouped = df.groupby('CustomQuarter')[['DailyViews', 'DailyMinutes']].sum()

方法2:向量化操作(超大数据量适用)

用向量化计算替代map,进一步提升效率:

start_month = 2
start_day = 27

# 生成每个索引对应的当年起始基准日
base_dates = pd.to_datetime(
    df.index.year.astype(str) + '-' + str(start_month) + '-' + str(start_day)
)
# 调整早于当年起始日的基准为上一年
base_dates = np.where(df.index < base_dates, base_dates - pd.DateOffset(years=1), base_dates)
base_dates = pd.DatetimeIndex(base_dates)

# 计算每个日期与基准日的季度间隔
quarters_since_base = ((df.index - base_dates) / pd.Timedelta(days=91)).astype(int) + 1
# 计算季度所属年份
quarter_years = base_dates.year + ((df.index - base_dates) / pd.Timedelta(days=365)).astype(int)

# 生成季度标签并分组求和
df['CustomQuarter'] = quarter_years.astype(str) + 'Q' + quarters_since_base.astype(str)
df_grouped = df.groupby('CustomQuarter').sum()

附加问题:设置"2022Q1"格式的索引

分组后直接用生成的CustomQuarter字符串作为索引,就是"YYYYQX"格式。如果索引是datetime类型,可通过格式化转换:

# 若索引为datetime类型,转为自定义格式
df_grouped.index = df_grouped.index.strftime('%YQ%q')

内容的提问来源于stack exchange,提问作者dg141

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:45:00