如何用Python按cust_id、sub_id分组计算支付月均并补全缺失月份生成目标dataframe
基于Pandas的实现方案
核心实现逻辑
- 按
cust_id + sub_id对原始数据分组,计算每组的总支付金额、首笔支付时间、末笔支付时间 - 对每个分组,从首笔支付所在自然月开始,到末笔支付所在自然月结束,生成连续的自然月序列
- 用分组总支付金额除以序列的月份总数,得到每月的平均支付额,为序列内每个自然月分配这个均值
完整可运行代码
首先导入依赖库:
import pandas as pd
构造题目给出的示例原始数据:
raw_data = [ (1, 'A', '12/1/20', 200), (1, 'A', '2/2/21', 200), (1, 'A', '2/3/21', 100), (1, 'A', '5/1/21', 200), (1, 'B', '1/2/21', 50), (1, 'B', '1/9/21', 20), (1, 'B', '3/1/21', 80), (1, 'B', '4/23/21', 90), (2, 'C', '1/4/21', 200), (2, 'C', '1/9/21', 300) ] df = pd.DataFrame(raw_data, columns=['cust_id', 'sub_id', 'date', 'payment'])
第一步:转换日期格式,让pandas可识别时间序列
df['date'] = pd.to_datetime(df['date'], format='%m/%d/%y')
第二步:分组聚合,计算每个用户+订阅组的核心统计指标
group_stats = df.groupby(['cust_id', 'sub_id'], as_index=False).agg( total_pay=('payment', 'sum'), # 组内累计总支付额 first_pay_date=('date', 'min'), # 组内最早的支付时间 last_pay_date=('date', 'max') # 组内最晚的支付时间 )
第三步:为每个组生成连续自然月的补全记录
def build_monthly_record(row): # 取首笔、末笔支付对应的当月第一天,作为月份区间的起点和终点 month_start = row['first_pay_date'].to_period('M').to_timestamp() month_end = row['last_pay_date'].to_period('M').to_timestamp() # 生成区间内所有自然月的第一天序列 month_series = pd.date_range(start=month_start, end=month_end, freq='MS') # 计算月均支付额,保留2位小数匹配示例格式 monthly_avg = round(row['total_pay'] / len(month_series), 2) # 返回该组对应的整段月度记录 return pd.DataFrame({ 'cust_id': row['cust_id'], 'sub_id': row['sub_id'], 'date': month_series, 'payment': monthly_avg }) # 拼接所有组的月度记录为最终结果表 result = pd.concat( group_stats.apply(build_monthly_record, axis=1).tolist(), ignore_index=True ) # 将日期转回和示例一致的字符串格式 result['date'] = result['date'].dt.strftime('%m/%d/%y')
实操注意事项
- 日期解析出错时,优先核对
pd.to_datetime的format参数是否和原始数据的日期规则匹配,比如原始日期为日/月/年格式时,需将format替换为%d/%m/%y - 不需要保留固定两位小数时,可直接调整
round函数的精度参数 - 无论组内支付记录是否存在跨月断档,生成的月份序列都是连续自然月,无需额外做缺失值填充
内容的提问来源于stack exchange,提问作者Yam
相关产品推荐
相关产品推荐

