如何基于同日邻近时刻与前两日相同时刻进行电力时序数据缺失值插补

如何基于同日邻近时刻与前两日相同时刻进行电力时序数据缺失值插补

Python

本文介绍一种针对电力负荷时间序列数据的精细化缺失值插补方法:对每个缺失点,综合考虑当日前后各2个相邻时间点(如01:00缺失时取00:00、00:30、01:30、02:00)、以及前2天同一时刻共5个有效观测值的均值进行填充。

本文介绍一种针对电力负荷时间序列数据的精细化缺失值插补方法:对每个缺失点,综合考虑当日前后各2个相邻时间点(如01:00缺失时取00:00、00:30、01:30、02:00)、以及前2天同一时刻共5个有效观测值的均值进行填充。

在电力负荷分析中,缺失值往往具有强时空相关性——同一电表的日间模式稳定,且相邻时刻及历史同期(如同一时刻前1–2天)的读数高度相似。简单使用全局均值或线性插值会忽略这一特性,导致插补偏差。本文提出一种时空协同插补策略:对任意缺失值 df.loc[i, col](col 为时间列如 '01:00'),构造候选值集合:

  • 同日邻近值:取该行所在日期(date)下,col 列前后各2个非空时间点(需确保列名按时间顺序排列);
  • 历史同期值:取该行 date - pd.Timedelta('1D') 和 date - pd.Timedelta('2D') 对应行中 col 列的值(若存在且非空);
  • 最终插补值:上述最多5个有效数值的算术平均值。

✅ 关键前提:时间列('00:00', '00:30', ..., '23:30')必须按升序排列,且 date 列为 datetime64 类型。

以下为完整实现代码(含健壮性处理):

import pandas as pd
import numpy as np

def impute_electricity_ts(df, time_cols=None):
    """
    基于同日邻近时刻 + 前2天同期时刻的均值插补电力时序缺失值

    Parameters:
    -----------
    df : pd.DataFrame
        输入DataFrame,含 'meter IDs', 'date' 及多个时间列(如 '00:00')
    time_cols : list of str, optional
        时间列名列表;若为None,则自动识别除 'meter IDs' 和 'date' 外的所有列

    Returns:
    --------
    pd.DataFrame : 插补后的DataFrame(原地修改并返回)
    """
    # 确保date列为datetime类型
    df = df.copy()
    df['date'] = pd.to_datetime(df['date'])

    # 自动识别时间列
    if time_cols is None:
        time_cols = [c for c in df.columns if c not in ['meter IDs', 'date']]

    # 按meter ID和date排序,确保时序连续
    df = df.sort_values(['meter IDs', 'date']).reset_index(drop=True)

    # 构建日期索引映射:{meter_id: {date: row_idx}}
    idx_map = {}
    for mid, group in df.groupby('meter IDs'):
        idx_map[mid] = {row['date']: idx for idx, row in group.iterrows()}

    # 遍历每个时间列
    for col in time_cols:
        for i in range(len(df)):
            if pd.isna(df.at[i, col]):
                mid = df.at[i, 'meter IDs']
                curr_date = df.at[i, 'date']

                candidates = []

                # 1. 同日邻近时刻(前后各2个)
                # 获取当前行所在日期的所有时间点值(非空)
                same_day_rows = df[(df['meter IDs'] == mid) & (df['date'] == curr_date)]
                if not same_day_rows.empty:
                    # 提取所有时间列值(转为Series便于索引)
                    time_series = same_day_rows.iloc[0][time_cols]
                    col_pos = time_cols.index(col)
                    # 前2个:max(0, col_pos-2) 到 col_pos-1
                    prev_pos = max(0, col_pos - 2)
                    for j in range(prev_pos, col_pos):
                        val = time_series.iloc[j]
                        if pd.notna(val):
                            candidates.append(val)
                    # 后2个:col_pos+1 到 min(len-1, col_pos+2)
                    next_pos = min(len(time_cols), col_pos + 3)
                    for j in range(col_pos + 1, next_pos):
                        val = time_series.iloc[j]
                        if pd.notna(val):
                            candidates.append(val)

                # 2. 前2天同期时刻
                for offset in [1, 2]:
                    ref_date = curr_date - pd.Timedelta(f'{offset}D')
                    if ref_date in idx_map[mid]:
                        ref_idx = idx_map[mid][ref_date]
                        val = df.at[ref_idx, col]
                        if pd.notna(val):
                            candidates.append(val)

                # 插补:取均值(至少1个候选值才填充,否则保持NaN)
                if candidates:
                    df.at[i, col] = np.mean(candidates)

    return df

# 使用示例
# 假设原始df已加载
# result_df = impute_electricity_ts(df)

注意事项与优化建议:

  • 性能提示:对大规模数据(>10万行),上述逐行循环可能较慢。可改用 groupby('meter IDs').apply() 并向量化内部逻辑,或借助 numba 加速。
  • 边界处理:首日/末日缺失值无法获取前2天数据,函数自动跳过;首/末时间点(如 '00:00' 或 '23:30')缺少前后邻近值,仅使用可用部分。
  • 扩展性:可通过参数 window_size=2 和 history_days=[1,2] 封装为通用接口,适配不同粒度(如15分钟)或历史窗口。
  • 验证建议:插补后建议绘制某电表连续多日的热力图(seaborn.heatmap),目视检查插补值是否符合日周期规律。

该方法兼顾物理可解释性与统计稳健性,在真实电力场景中显著优于单一维度插补,是负荷数据预处理的推荐实践。

本文地址:https://www.sztg.com.cn/article/672276.html

如非特殊说明,本站内容均来自于网友自主分享,如有任何问题均请联系我们进行处理!

猜您喜欢