如何基于闰年/平年自动复制Pandas时序DataFrame数据?
解决方法
核心思路
问题根源是平年比闰年少1天(2月29日),对应15分钟间隔的数据少96行,直接复制原闰年数据会导致总行数与目标时间索引不匹配。正确的做法是根据目标年份的闰年属性,动态复用原数据:非2月直接复用,2月则根据年份是否闰年保留/剔除29日数据。
方法一:索引映射法(简洁高效)
利用Pandas的日期索引映射,自动适配平年闰年的日期差异:
import pandas as pd # 确保原df的索引为datetime类型(如果还不是的话) df.index = pd.to_datetime(df.index) # 生成2012-2022年完整的15分钟时间索引(自动跳过平年2月29日) target_index = pd.date_range(start="2012-01-01 00:00", end="2022-12-31 23:45", freq="15T") # 将每个目标时间点映射到2012年的对应日期(月/日/时间一致) map_to_2012 = target_index.map(lambda dt: dt.replace(year=2012)) # 从原df中提取对应数据,并设置目标索引 df_until_2022 = df.loc[map_to_2012].reset_index(drop=True) df_until_2022.index = target_index
原理说明
pd.date_range会自动处理平年闰年:平年不会生成2月29日的15分钟时间点,确保目标索引的行数与实际需要的一致。- 通过
replace(year=2012)将目标时间点转换为2012年的对应时刻,原df(2012年闰年数据)包含所有平年的日期,因此可以直接匹配取值。
方法二:分年月循环法(灵活可扩展)
如果需要对特定年份/月份做自定义调整,可拆分原数据的月份,逐个年份拼接:
import pandas as pd # 确保原df索引为datetime类型 df.index = pd.to_datetime(df.index) # 拆分原df为12个月份的子DataFrame month_dfs = {month: df[df.index.month == month] for month in range(1, 13)} all_year_data = [] # 遍历2012-2022年的每个年份 for year in range(2012, 2023): year_month_data = [] # 判断当前年份是否为闰年 is_leap_year = pd.Timestamp(f"{year}-02-29").is_leap_year for month in range(1, 13): month_data = month_dfs[month].copy() # 替换年份为当前年份 month_data.index = month_data.index.map(lambda dt: dt.replace(year=year)) if month == 2 and not is_leap_year: # 平年2月:剔除29日的数据 month_data = month_data[month_data.index.day != 29] year_month_data.append(month_data) # 合并当前年份的所有月份数据 all_year_data.append(pd.concat(year_month_data)) # 合并所有年份的数据 df_until_2022 = pd.concat(all_year_data)
适用场景
当需要对某些年份的特定月份(如2020年2月需额外调整数据)做个性化修改时,这种方式更易扩展。
为什么之前的方法失效?
原代码pd.concat([df]*10, ignore_index=True)直接复制了10次2012年的闰年数据(共366*96=35136行),但2012-2022年实际总天数为:
- 闰年:2012、2016、2020(共3年)
- 平年:2013、2014、2015、2017、2018、2019、2021、2022(共8年)
总行数应为3*366*96 + 8*365*96 = (3*366+8*365)*96 = 3652*96=350592行,而复制10次的总行数是10*35136=351360行,两者相差768行(8个平年各少96行),因此无法匹配目标索引。
内容的提问来源于stack exchange,提问作者jess
相关产品推荐
相关产品推荐

