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

在Pandas中按行匹配日期范围求和日销售值至月度付款列

解决Pandas中自定义日历下的日期范围求和问题

嘿,这个需求确实有点棘手,尤其是那个特殊的35/28/28天循环的月份规则,不过咱们一步步拆解来搞定它:

核心思路

因为常规日期系统不匹配你的自定义月份天数,所以我们得先把所有日期转换成基于自定义日历的绝对累计天数,这样就能轻松判断某个日期是否落在指定的付款起止月份范围内,最后再对符合条件的sample_sales求和。

具体步骤&代码实现

1. 定义自定义日历的天数映射

首先我们要把每个“月份”转换成对应的绝对天数区间,比如第1个月是0-34天(共35天),第2个月是35-62天(28天),第3个月是63-90天(28天),第4个月又回到35天的循环,以此类推:

import pandas as pd
import numpy as np

# 自定义月份天数循环规则
month_days_cycle = [35, 28, 28]

# 输入月份数,返回该月份对应的绝对天数起始和结束值
def get_month_date_range(month_num):
    cycle_length = len(month_days_cycle)
    # 确定当前月份在循环中的位置
    cycle_idx = (month_num - 1) % cycle_length
    # 计算当前月份之前所有月份的总天数
    total_days_before = sum(
        month_days_cycle[(i-1) % cycle_length] 
        for i in range(1, month_num)
    )
    start_day = total_days_before
    end_day = total_days_before + month_days_cycle[cycle_idx] - 1
    return start_day, end_day

2. 转换日期列与付款起止列

假设你的数据中:

  • date列是类似"1-5"(第1个月第5天)的格式,或者是拆分好的月份+天数字段
  • payment_start和payment_end是月份编号(比如1代表第1个月)

我们把这些都转换成绝对天数:

# 给数据添加付款起止的绝对天数列
df['payment_start_abs'] = df['payment_start'].apply(lambda x: get_month_date_range(x)[0])
df['payment_end_abs'] = df['payment_end'].apply(lambda x: get_month_date_range(x)[1])

# 把date列转换成绝对天数(这里假设date是"月-日"格式,可根据你的实际格式调整)
def date_to_absolute_day(date_str):
    month, day = map(int, date_str.split('-'))
    month_start, _ = get_month_date_range(month)
    return month_start + day - 1

df['date_abs'] = df['date'].apply(date_to_absolute_day)

3. 计算符合条件的销售额总和

这里提供两种实现方式,按需选择:

方式一:用apply(适合小数据集,逻辑直观)

对每一行,筛选出所有日期落在当前行付款范围内的记录,然后求和:

def calculate_monthly_payment(row):
    # 生成筛选掩码:date_abs在当前行的付款起止范围内
    mask = (df['date_abs'] >= row['payment_start_abs']) & (df['date_abs'] <= row['payment_end_abs'])
    return df.loc[mask, 'sample_sales'].sum()

df['monthly_payment'] = df.apply(calculate_monthly_payment, axis=1)
方式二:用区间连接(适合大数据集,效率更高)

利用Pandas的IntervalIndex做区间匹配,避免逐行循环:

# 先按日期聚合销售额(如果同一个日期有多条记录的话)
date_sales = df[['date_abs', 'sample_sales']].groupby('date_abs').sum().reset_index()

# 生成付款起止的区间索引
payment_intervals = pd.IntervalIndex.from_arrays(
    df['payment_start_abs'], 
    df['payment_end_abs'], 
    closed='both'  # 包含起止日期
)

# 按区间分组求和,再映射回原数据
interval_sums = date_sales.groupby(
    pd.cut(date_sales['date_abs'], payment_intervals)
)['sample_sales'].sum()

# 把结果赋值给monthly_payment列
df['monthly_payment'] = interval_sums.reindex(payment_intervals).values

注意事项

  • 如果你的date列格式不是"月-日",可以调整date_to_absolute_day函数的逻辑,比如如果是单独的month和day列,直接传入这两个值即可。
  • 如果payment_start和payment_end不是月份编号,而是其他格式(比如自定义的日期字符串),需要先把它们转换成对应的月份数再处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:03:36