Python/Pandas基于ID生成起止月区间内的新行并制作透视表
Pandas 按日期间隔展开行并生成月度透视表解决方案
步骤1:日期格式预处理
先把start_date和end_date列转换为pandas可识别的日期类型,方便后续生成连续月份序列:
import pandas as pd # 示例数据构造,可直接替换为你的实际数据源 df = pd.DataFrame({ 'id': [477,518,553,925,948,971,987,117,117,133], 'start_date': ['2020-02','2020-08','2020-03','2020-07','2020-05','2020-02','2020-01','2020-06','2020-05','2020-05'], 'end_date': ['2020-04','2020-08','2020-04','2020-09','2020-06','2020-07','2020-02','2020-07','2020-07','2020-06'] }) # 转换为日期格式 df['start_date'] = pd.to_datetime(df['start_date']) df['end_date'] = pd.to_datetime(df['end_date'])
步骤2:按月份范围展开为多行
为每行生成start_date到end_date之间的所有月份列表,再通过explode拆分为独立行:
# 生成每行覆盖的月份列表,输出为YYYY-MM格式 df['month_list'] = df.apply( lambda x: pd.date_range(start=x['start_date'], end=x['end_date'], freq='MS').strftime('%Y-%m').tolist(), axis=1 ) # 拆分为多行,仅保留需要的id和月份字段 df_expanded = df.explode('month_list')[['id', 'month_list']].rename(columns={'month_list': 'dates'})
此时df_expanded结构和你给出的示例完全一致,每个id对应范围内的所有月份都会生成独立行。
如果你同一个id存在重复的月份区间,且需要结果仅标记「是否存在」(最大值为1),可以新增一步去重:
df_expanded = df_expanded.drop_duplicates()
步骤3:生成透视表
直接用crosstab即可快速生成你需要的0-1透视表,写法比pivot_table更简洁:
pivot_result = pd.crosstab( index=df_expanded['id'], columns=df_expanded['dates'], dropna=False ).reindex(sorted(df_expanded['dates'].unique()), axis=1, fill_value=0)
如果要保留你原来的pivot_table写法,调整为如下即可得到完全一致的结果:
pivot_result = pd.pivot_table( df_expanded, index='id', columns='dates', aggfunc='size', fill_value=0 )
输出结果完全符合你的预期,单元格值为1代表对应id在该月份处于有效期内,0代表不在。
内容的提问来源于stack exchange,提问作者bellotto
相关产品推荐
相关产品推荐

