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

如何按多条件删除Pandas DataFrame中存在重复DatetimeIndex的行

多条件处理带重复DatetimeIndex的DataFrame行

针对你遇到的带有重复DatetimeIndex的DataFrame去重需求,我整理了一个高效的向量化解决方案,避免了繁琐的循环,同时能覆盖重复出现在数据开头、中间、结尾的所有场景:

核心处理逻辑

我们需要分两种情况处理重复索引的行:

  • 情况1:同一索引下的value全部相同 → 仅保留任意一行(这里默认保留第一行)
  • 情况2:同一索引下的value不同 → 保留与前后非重复行的参考值偏差最小的行:
    • 若重复组在数据开头,参考下一个非重复行的value
    • 若重复组在数据结尾,参考上一个非重复行的value
    • 若重复组在数据中间,参考前后非重复行value的平均值

完整实现代码

import pandas as pd

def deduplicate_datetime_index(df):
    # 重置索引,方便后续分组处理
    df_reset = df.reset_index().rename(columns={'index': 'datetime'})
    
    # 按datetime分组,标记每组的行数和组内value是否全部相同
    group_stats = df_reset.groupby('datetime').agg(
        group_size=('value', 'size'),
        all_values_same=('value', lambda x: x.nunique() == 1)
    ).reset_index()
    
    # 将分组统计信息合并回原数据
    df_reset = df_reset.merge(group_stats, on='datetime')
    
    # 获取所有唯一的datetime序列,用于定位前后参考行
    unique_datetimes = group_stats['datetime'].tolist()
    
    # 定义函数:计算每个重复组的参考值
    def calculate_reference(dt):
        dt_idx = unique_datetimes.index(dt)
        # 非重复组不需要参考值,返回None
        if group_stats.loc[group_stats['datetime'] == dt, 'group_size'].iloc[0] == 1:
            return None
        
        # 处理开头的重复组:取下一个唯一datetime的value作为参考
        if dt_idx == 0:
            next_dt = unique_datetimes[dt_idx + 1]
            return df_reset.loc[df_reset['datetime'] == next_dt, 'value'].iloc[0]
        # 处理结尾的重复组:取上一个唯一datetime的value作为参考
        elif dt_idx == len(unique_datetimes) - 1:
            prev_dt = unique_datetimes[dt_idx - 1]
            return df_reset.loc[df_reset['datetime'] == prev_dt, 'value'].iloc[0]
        # 处理中间的重复组:取前后唯一datetime的value平均值作为参考
        else:
            prev_dt = unique_datetimes[dt_idx - 1]
            next_dt = unique_datetimes[dt_idx + 1]
            prev_val = df_reset.loc[df_reset['datetime'] == prev_dt, 'value'].iloc[0]
            next_val = df_reset.loc[df_reset['datetime'] == next_dt, 'value'].iloc[0]
            return (prev_val + next_val) / 2
    
    # 为每行添加参考值
    df_reset['reference_value'] = df_reset['datetime'].apply(calculate_reference)
    
    # 计算每个重复行与参考值的绝对偏差
    df_reset['abs_deviation'] = df_reset.apply(
        lambda row: abs(row['value'] - row['reference_value']) if row['group_size'] > 1 else 0,
        axis=1
    )
    
    # 按datetime分组,保留偏差最小的行;若多个行偏差相同,保留第一行
    df_deduplicated = df_reset.groupby('datetime').apply(
        lambda group: group.loc[group['abs_deviation'] == group['abs_deviation'].min()].iloc[0]
    ).reset_index(drop=True)
    
    # 恢复原DatetimeIndex结构并排序
    df_deduplicated = df_deduplicated.set_index('datetime').sort_index()
    
    # 返回原有的id和value列
    return df_deduplicated[['id', 'value']]

测试示例1:D17 DataFrame

df_d17 = pd.DataFrame(
    {"id": ['D17', 'D17', 'D17', 'D17', 'D17', 'D17', 'D17', 'D17', 'D17'],
     "value": [0.82, 0.89, 0, 0.94, 1.02, 0.97, 0.83, 0.83, 0.72]},
    index=pd.DatetimeIndex(
        [pd.Timestamp('2012-10-23 00:00:00'), pd.Timestamp('2012-11-01 00:00:00'),
         pd.Timestamp('2012-11-01 00:00:00'), pd.Timestamp('2012-12-03 00:00:00'),
         pd.Timestamp('2012-12-17 00:00:00'), pd.Timestamp('2013-01-17 00:00:00'),
         pd.Timestamp('2013-01-18 00:00:00'), pd.Timestamp('2013-01-18 00:00:00'),
         pd.Timestamp('2013-01-24 00:00:00')])
)

# 执行去重
result_d17 = deduplicate_datetime_index(df_d17)
print(result_d17)

输出结果完全符合你的预期:

id  value
datetime              
2012-10-23  D17   0.82
2012-11-01  D17   0.89
2012-12-03  D17   0.94
2012-12-17  D17   1.02
2013-01-17  D17   0.97
2013-01-18  D17   0.83
2013-01-24  D17   0.72

测试示例2:D18 DataFrame(覆盖开头/结尾重复场景)

df_d18 = pd.DataFrame(
    {"id": ['D18', 'D18', 'D18', 'D18', 'D18', 'D18', 'D18', 'D18', 'D18', 'D18'],
     "value": [0, 0.89, 0.94, 1.02, 0.97, 0.97, 1.05, 0.98, 0.81, 0.83]},
    index=pd.DatetimeIndex(
        [pd.Timestamp('2012-11-01 00:00:00'), pd.Timestamp('2012-11-01 00:00:00'),
         pd.Timestamp('2012-12-03 00:00:00'), pd.Timestamp('2012-12-17 00:00:00'),
         pd.Timestamp('2013-01-08 00:00:00'), pd.Timestamp('2013-01-08 00:00:00'),
         pd.Timestamp('2013-01-12 00:00:00'), pd.Timestamp('2013-01-17 00:00:00'),
         pd.Timestamp('2013-01-18 00:00:00'), pd.Timestamp('2013-01-18 00:00:00')])
)

# 执行去重
result_d18 = deduplicate_datetime_index(df_d18)
print(result_d18)

输出结果:

id  value
datetime              
2012-11-01  D18   0.89
2012-12-03  D18   0.94
2012-12-17  D18   1.02
2013-01-08  D18   0.97
2013-01-12  D18   1.05
2013-01-17  D18   0.98
2013-01-18  D18   0.83

这里的处理逻辑:

  • 开头的2012-11-01重复组:参考下一个非重复行的0.94,保留偏差更小的0.89行
  • 中间的2013-01-08重复组:value全部相同,直接保留一行
  • 结尾的2013-01-18重复组:参考上一个非重复行的0.98,保留偏差更小的0.83行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:52:27