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

Pandas使用shift按月份偏移遇重复索引错误,求解决方案

解决Pandas中日期索引DataFrame添加上月/上年聚合列时的重复索引错误

问题分析

你遇到的ValueError: cannot reindex on an axis with duplicate labels,本质是原DataFrame的索引为每日级别的唯一日期,而shift(periods=1, freq='ME')会把所有日期偏移至对应月份的月末,导致偏移后的Series出现大量重复的月末索引(比如2013-11的所有日期都会被偏移到2013-12-31),无法与原DataFrame的唯一日期索引对齐。

解决方案

核心思路是先提取唯一的月度/年度聚合值,再将上月/上年的值映射回原DataFrame的每一行,避免直接对每日索引做频率偏移。

方法1:用Resample生成映射表(简洁高效)

import pandas as pd

# ---------------------- 生成previous_month列 ----------------------
# 提取唯一月度数据(以月末为索引,取每个月最后一条的monthly_sum,同月份值一致)
monthly_agg = tdf['monthly_sum'].resample('ME').last()
# 生成上月数据,转为年月-值的字典
prev_month_map = monthly_agg.shift(1).reset_index()
prev_month_map['year_month'] = prev_month_map['Date Enrolled'].dt.strftime('%Y-%m')
prev_month_dict = prev_month_map.set_index('year_month')['monthly_sum'].to_dict()
# 将原DataFrame日期转为年月字符串,映射上月值
tdf['previous_month'] = tdf.index.strftime('%Y-%m').map(prev_month_dict)

# ---------------------- 生成previous_year列 ----------------------
# 提取唯一年度数据(以年末为索引)
yearly_agg = tdf['monthly_sum'].resample('YE').last()
# 生成上年数据,转为年份-值的字典
prev_year_map = yearly_agg.shift(1).reset_index()
prev_year_map['year'] = prev_year_map['Date Enrolled'].dt.strftime('%Y')
prev_year_dict = prev_year_map.set_index('year')['monthly_sum'].to_dict()
# 映射上年值
tdf['previous_year'] = tdf.index.strftime('%Y').map(prev_year_dict)

方法2:用字符串处理年月(直观易理解)

# ---------------------- 生成previous_month列 ----------------------
# 给原DataFrame添加年月标识列
tdf['year_month'] = tdf.index.strftime('%Y-%m')
# 提取每个年月的唯一月度总和
monthly_dict = tdf.groupby('year_month')['monthly_sum'].first().to_dict()
# 定义函数生成上月的年月字符串
def get_prev_month(ym_str):
    year, month = map(int, ym_str.split('-'))
    return f"{year-1}-12" if month == 1 else f"{year}-{month-1:02d}"
# 映射上月值
tdf['previous_month'] = tdf['year_month'].apply(get_prev_month).map(monthly_dict)

# ---------------------- 生成previous_year列 ----------------------
# 添加年份标识列
tdf['year'] = tdf.index.strftime('%Y')
# 提取每个年份的唯一年度总和
yearly_dict = tdf.groupby('year')['monthly_sum'].sum().to_dict()
# 生成上年字符串并映射
tdf['previous_year'] = tdf['year'].astype(int).sub(1).astype(str).map(yearly_dict)

关键说明

  • 两种方法都绕开了直接对每日索引的频率偏移操作,先聚合出唯一的月度/年度值,再通过年月/年份标识映射回原数据,彻底解决重复索引问题。
  • 如果你的monthly_sum在同一个月内完全一致,用groupby().first()或resample().last()提取唯一值的结果无差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:52:35