Pandas按name_id补全缺失时间行并去重问题求助
解决Pandas分组补全小时时间序列并保留name_id的问题
嘿,作为Pandas新手碰到这种时间序列补全的问题确实容易卡壳,我来帮你一步步搞定这个需求!咱们既要补全每个name_id下当日00:00-23:00的缺失小时行,还要去重(包括夏令时导致的重复时间),最后还得保留name_id列不丢失,安排!
整体思路拆解
- 先把时间列解析正确:尤其是你的输入是
dd/mm/yyyy格式,得指定解析规则,还要考虑时区(应对夏令时的时间变化)。 - 彻底移除重复行:不管是普通重复还是夏令时导致的同一小时重复,都通过
name_id+datetime的组合去重。 - 分组补全小时序列:按
name_id+日期分组,给每个组生成当日完整的24小时序列,再和原数据合并补NaN。 - 整理成你要的输出格式:把每个
name_id对应日期的value列表整理好,同时保留name_id。
完整代码实现
import pandas as pd import numpy as np # 先把你的示例输入转成DataFrame data = { 'name_id': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B'], 'datetime': ['23/01/2020 0:00:00', '23/01/2020 1:00:00', '23/01/2020 2:00:00', '23/01/2020 3:00:00', '23/01/2020 3:00:00', '23/01/2020 4:00:00', '23/01/2020 5:00:00', '23/01/2020 0:00:00', '23/01/2020 1:00:00', '23/01/2020 2:00:00', '23/01/2020 3:00:00', '23/01/2020 6:00:00'], 'value': [100, 98, 96, 99, 99, 98, 99, 144, 324, 367, 368, 364] } df = pd.DataFrame(data) # 1. 解析时间列:指定格式为dd/mm/yyyy HH:MM:SS,添加时区(这里用欧洲伦敦时区,可根据你的数据调整) # 加时区是为了正确识别夏令时的时间变化,避免处理重复行出错 df['datetime'] = pd.to_datetime(df['datetime'], format='%d/%m/%Y %H:%M:%S', tz='Europe/London') # 2. 移除重复行:按name_id和datetime组合去重,保留第一行 df = df.drop_duplicates(subset=['name_id', 'datetime'], keep='first') # 3. 定义补全小时序列的函数 def fill_hourly_group(group): # 获取当前组的日期(同一组的日期都是相同的) current_date = group['datetime'].dt.date.iloc[0] # 生成当日00:00到23:00的完整小时序列 full_hour_range = pd.date_range( start=f"{current_date} 00:00:00", end=f"{current_date} 23:00:00", freq='H', tz='Europe/London' ) # 转成DataFrame用于合并 full_hour_df = pd.DataFrame({'datetime': full_hour_range}) # 和原组数据合并,缺失的value自动设为NaN merged_df = pd.merge(full_hour_df, group, on='datetime', how='left') # 给合并后的df填充name_id(同一组的name_id相同) merged_df['name_id'] = group['name_id'].iloc[0] return merged_df # 按name_id和日期分组,应用补全函数 df['date'] = df['datetime'].dt.date filled_result = df.groupby(['name_id', 'date']).apply(fill_hourly_group).reset_index(drop=True) # 删掉临时的date列 filled_result = filled_result.drop('date', axis=1) # 4. 整理成每个name_id对应日期的value列表(按需选择) final_output = filled_result.groupby( ['name_id', filled_result['datetime'].dt.date] )['value'].apply(list).reset_index() final_output.columns = ['name_id', 'date', 'value_list'] # 打印看看结果 print(final_output)
关键说明
- 之前的参考代码丢失
name_id,是因为分组后只对value列应用函数,没有保留组内的name_id信息。咱们的函数里通过group['name_id'].iloc[0]给补全后的行填充了对应的name_id,就不会丢失啦。 - 时区的设置很重要:如果你的数据涉及夏令时(比如时钟回拨导致同一小时出现两次),带时区的datetime能帮你正确识别这些重复时间,去重更准确。如果你的数据没有时区,可以去掉
tz参数,但要注意夏令时场景的处理。
内容的提问来源于stack exchange,提问作者Agus
相关产品推荐
相关产品推荐

