如何将单次购买记录转换为按邮政编码分组的月度累计购买量并补全无交易月份
解决按邮政编码计算每月累计购买量(含无交易月份)的问题
咱们可以用Python的pandas库来完美解决这个需求,核心思路是先补全每个邮政编码对应的所有连续月份,再计算累计购买量。下面一步步来实现:
步骤1:准备并清洗原始数据
首先,原始数据里有个无效日期2019-2-30(2月没有30号),咱们先把它修正为合理的日期(比如2019-02-28),然后把Date列转为datetime类型:
import pandas as pd # 原始数据集 data = { 'ID': [1,2,3,4,5,6,7,8], 'Zipcode': [9999,9999,9999,9999,2400,2400,2400,2400], 'Date': ['2018-12-24','2018-12-26','2019-3-14','2019-4-8','2018-12-12','2018-12-14','2019-1-15','2019-2-30'], 'Purchase': [1,1,1,1,1,1,1,1] } df = pd.DataFrame(data) # 修正无效日期并转为datetime类型 df['Date'] = pd.to_datetime(df['Date'], errors='coerce') # 把无效的2019-02-30替换为2019-02-28 df['Date'] = df['Date'].fillna(pd.to_datetime('2019-02-28'))
步骤2:按邮编和月份聚合购买量
接下来,提取每个日期对应的年月(用Period类型更方便处理月份),然后按Zipcode和Period分组,计算每月的购买总量:
# 生成年月周期列 df['Period'] = df['Date'].dt.to_period('M') # 按邮编和月份分组,计算每月购买量 monthly_purchases = df.groupby(['Zipcode', 'Period'])['Purchase'].sum().reset_index()
步骤3:补全每个邮编的所有连续月份
现在需要为每个邮编生成从最早月份到最晚月份的完整月份序列,确保没有缺失的月份:
# 获取每个邮编的时间范围 date_ranges = monthly_purchases.groupby('Zipcode')['Period'].agg(['min', 'max']) # 生成每个邮编的完整月份序列 full_periods = [] for zipcode, row in date_ranges.iterrows(): periods = pd.period_range(row['min'], row['max'], freq='M') full_periods.extend([(zipcode, p) for p in periods]) full_periods_df = pd.DataFrame(full_periods, columns=['Zipcode', 'Period'])
步骤4:合并数据并计算累计购买量
把完整月份序列和每月购买量合并,缺失的购买量填充为0,然后按邮编分组计算累计和:
# 合并数据,填充缺失的购买量为0 merged_df = pd.merge(full_periods_df, monthly_purchases, on=['Zipcode', 'Period'], how='left') merged_df['Purchase'] = merged_df['Purchase'].fillna(0) # 计算累计购买量 merged_df['Cumulative purchases'] = merged_df.groupby('Zipcode')['Purchase'].cumsum().astype(int) # 把Period格式转为用户需要的"Month Year"形式 merged_df['Period'] = merged_df['Period'].dt.strftime('%B %Y') # 整理成目标格式 result_df = merged_df[['Zipcode', 'Period', 'Cumulative purchases']] print(result_df)
运行这段代码后,就能得到你想要的结果:
Zipcode Period Cumulative purchases 0 9999 December 2018 2 1 9999 January 2019 2 2 9999 February 2019 2 3 9999 March 2019 3 4 9999 April 2019 4 5 2400 December 2018 2 6 2400 January 2019 3 7 2400 February 2019 4 8 2400 March 2019 4 9 2400 April 2019 4
(注:如果需要扩展到更晚的月份,只需要调整pd.period_range的结束日期即可)
内容的提问来源于stack exchange,提问作者TvCasteren
相关产品推荐
相关产品推荐

