基于缓存规则的DataFrame去重:按ID与日期规则清理重复行
Pandas按ID和日期规则去重:保留非基准日/次日的行
问题描述
我有一个包含ID和Datetime两列的DataFrame,需要根据Datetime列对同一ID的行进行筛选去重。规则为:以某一行的日期为基准,后续行若日期是基准日当天或次日23:59:59之前,则删除该行;找到第一个不在此范围的行作为新基准,重复此逻辑。
原始DataFrame
| ID | Datetime |
|---|---|
| 100 | 2023-05-01 10:00:00 |
| 100 | 2023-05-01 11:00:00 |
| 100 | 2023-05-01 15:00:00 |
| 100 | 2023-05-02 17:00:00 |
| 100 | 2023-05-02 23:59:59 |
| 100 | 2023-05-03 01:00:00 |
| 100 | 2023-05-03 05:00:00 |
| 200 | 2023-05-01 15:00:00 |
| 200 | 2023-05-01 18:00:00 |
| 200 | 2023-05-02 12:00:00 |
| 200 | 2023-05-03 07:00:00 |
预期结果
| ID | Datetime |
|---|---|
| 100 | 2023-05-01 10:00:00 |
| 100 | 2023-05-03 01:00:00 |
| 200 | 2023-05-01 15:00:00 |
| 200 | 2023-05-03 07:00:00 |
我尝试过移位行、计算时间差的方法,但没解决问题。
解决方案
核心思路
按ID分组后,迭代确定保留的基准行:
- 先将
Datetime列转为datetime类型,保证时间运算的准确性 - 对每个ID的时间序列排序(避免原始数据顺序混乱导致逻辑错误)
- 从第一个行开始标记为保留,跳过所有在基准日当天或次日23:59:59之前的行,找到下一个符合条件的行作为新基准,重复此过程
代码实现
import pandas as pd # 构造原始数据 data = { 'ID': [100,100,100,100,100,100,100,200,200,200,200], 'Datetime': ['2023-05-01 10:00:00','2023-05-01 11:00:00','2023-05-01 15:00:00', '2023-05-02 17:00:00','2023-05-02 23:59:59','2023-05-03 01:00:00', '2023-05-03 05:00:00','2023-05-01 15:00:00','2023-05-01 18:00:00', '2023-05-02 12:00:00','2023-05-03 07:00:00'] } df = pd.DataFrame(data) # 转换为datetime类型 df['Datetime'] = pd.to_datetime(df['Datetime']) # 按ID和时间排序,确保时间顺序正确 df = df.sort_values(['ID', 'Datetime']).reset_index(drop=True) # 定义分组筛选函数 def filter_group(group): keep_indices = [] current_idx = 0 n = len(group) while current_idx < n: # 保留当前基准行 keep_indices.append(current_idx) # 计算截止时间:基准日次日的23:59:59 base_date = group.iloc[current_idx]['Datetime'].date() cutoff_time = pd.Timestamp(base_date + pd.Timedelta(days=1)) + pd.Timedelta(hours=23, minutes=59, seconds=59) # 找到第一个超出截止时间的行索引 next_idx = current_idx + 1 while next_idx < n and group.iloc[next_idx]['Datetime'] <= cutoff_time: next_idx += 1 current_idx = next_idx return group.iloc[keep_indices] # 分组应用筛选逻辑 result_df = df.groupby('ID', group_keys=False).apply(filter_group) print(result_df)
代码说明
- 时间类型转换:确保
Datetime列可以进行时间比较和运算 - 排序处理:保证每个ID下的时间是按先后顺序排列的,避免筛选逻辑出错
- 迭代筛选:通过循环逐个确定基准行,跳过所有符合删除条件的行,直到遍历完当前ID的所有行
- 分组应用:对每个ID独立执行筛选逻辑,最后合并结果得到目标DataFrame
内容的提问来源于stack exchange,提问作者Leonardo Vieira
相关产品推荐
相关产品推荐

