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

如何基于闰年/平年自动复制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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:20:28