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

Pandas处理夏令时导致时间戳重复无法设为索引问题

问题:夏令时导致重复时间戳,无法设置索引并补全时间序列

我用pandas读取CSV文件,文件包含时间戳(格式如31/12/2022 21:30)和浮点能耗值两列,数据由每15分钟记录一次的仪器生成。设备故障会导致部分时段记录缺失,我需要补全这些缺口(用0值或后续均值分摊)。但2022年10月30日夏令时切换时出现重复时间戳,无法将时间列设为索引;转换时区到Europe/Madrid后仍无效,执行代码时在set_index步骤报错cannot reindex a non-unique index with a method or limit,且时间列不显示时区标识(+01/+02)。

原代码:

telemedida_df=pd.read_csv("filename.csv",delimiter=";",decimal=",")
telemedida_df["Fecha/hora"]=pd.to_datetime(telemedida_df["Fecha/hora"],format='%d/%m/%Y %H:%M',utc=True)
telemedida_df["Fecha/hora"] = telemedida_df["Fecha/hora"].dt.tz_convert('Europe/Madrid')
df_new = (telemedida_df.assign(date=telemedida_df["Fecha/hora"].dt.date)   #create new col 'date' from the timestamp
            .set_index("Fecha/hora")   #Error here           
            .groupby('date')                    
            .apply(lambda x: x.resample('15Min')  
                   .ffill())                    
            .reset_index('date', drop=True)      
            .drop('date',1)                     
            .reset_index()                       
         ) 

CSV示例数据(西班牙逗号作为小数分隔符):

Fecha/hora;Consumo
30/10/2022 0:15;6,9
30/10/2022 0:30;6,6
30/10/2022 0:45;6,7
30/10/2022 1:00;6,7
30/10/2022 1:15;6,6
30/10/2022 1:30;6,9
30/10/2022 1:45;6,8
30/10/2022 2:00;6,7
30/10/2022 2:15;6,6
30/10/2022 2:30;6,7
30/10/2022 2:45;6,7
30/10/2022 2:00;6,7
30/10/2022 2:15;6,7
30/10/2022 2:30;6,8
30/10/2022 2:45;6,7
30/10/2022 3:00;6,8
30/10/2022 3:15;6,8
30/10/2022 3:30;6,6
30/10/2022 3:45;7
30/10/2022 4:00;6,6
30/10/2022 4:15;6,8
30/10/2022 4:30;6,6
30/10/2022 4:45;6,7
30/10/2022 5:00;6,6
解决方案:处理夏令时重复时间戳并补全序列

1. 正确解析带时区的时间戳

原代码错误在于直接用utc=True解析本地时间,应先解析为无时区的本地时间,再指定时区为Europe/Madrid,同时用ambiguous='infer'让pandas自动推断夏令时切换的重复时间:

import pandas as pd

# 读取CSV,正确处理分隔符和小数格式
telemedida_df = pd.read_csv("filename.csv", delimiter=";", decimal=",")

# 先解析为本地时间,再绑定Europe/Madrid时区,自动处理夏令时重复
telemedida_df["Fecha/hora"] = pd.to_datetime(telemedida_df["Fecha/hora"], format='%d/%m/%Y %H:%M')
telemedida_df["Fecha/hora"] = telemedida_df["Fecha/hora"].dt.tz_localize('Europe/Madrid', ambiguous='infer')

2. 手动处理残留重复项(可选)

如果ambiguous='infer'仍有重复时间戳,可合并重复项的能耗值(比如取均值):

# 检查并处理重复时间戳
duplicate_mask = telemedida_df.duplicated(subset="Fecha/hora", keep=False)
if duplicate_mask.any():
    # 合并重复时间的能耗值,取均值
    telemedida_df = telemedida_df.groupby("Fecha/hora").agg({"Consumo": "mean"}).reset_index()

3. 生成完整时间序列并补全缺失值

现在可以设置索引,生成15分钟间隔的完整序列,按需补全缺失值:

# 设置时间索引
telemedida_df = telemedida_df.set_index("Fecha/hora")

# 生成覆盖数据起止时间的完整15分钟序列
full_time_index = pd.date_range(
    start=telemedida_df.index.min(),
    end=telemedida_df.index.max(),
    freq='15min',
    tz='Europe/Madrid'
)

# 补全缺失值:这里用0填充,也可替换为ffill()/bfill()或滚动均值
df_completed = telemedida_df.reindex(full_time_index, fill_value=0)

# 示例:用后续4个时段的均值分摊缺失值
# df_completed['Consumo'] = df_completed['Consumo'].fillna(df_completed['Consumo'].rolling(4, min_periods=1).mean())

# 重置索引(可选,将时间列恢复为普通列)
df_completed = df_completed.reset_index().rename(columns={"index": "Fecha/hora"})

关键说明

  • tz_localize vs tz_convert:tz_localize是给无时区时间戳添加时区信息,tz_convert是转换已有时区的时间到其他时区,原代码用反导致时区识别错误。
  • ambiguous='infer':夏令时切换(西班牙10月最后一个周日)会出现重复本地时间,该参数让pandas根据序列顺序推断时间对应的实际UTC值,生成唯一时区索引。
  • 补全方式可灵活选择:直接填0、向前填充、滚动均值、线性插值等,按需调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:13:09