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

如何在Pandas GroupBy对象中使用IF NOT IN逻辑补全数据

问题描述

我有如下DataFrame:

import pandas as pd
import numpy as np
# create a sample DataFrame
data = {'ID': [1, 1, 1, 2, 2, 2],
        'timestamp': ['2022-01-01 12:00:00', '2022-01-01 13:00:00', '2022-01-01 18:00:00',
                      '2022-01-01 12:02:00', '2022-01-01 13:02:00', '2022-01-01 18:02:00'],
        'value1': [10, 20, 30, 40, 50, 60],
        'gender': ['M', 'M', 'F', 'F', 'F', 'M'],
        'age': [20, 25, 30, 35, 40, 45]}
df = pd.DataFrame(data)

# extract the date from the timestamp column
df['date'] = pd.to_datetime(df['timestamp']).dt.date

我希望遍历该DataFrame的所有timestamp值,检查每个timestamp在对应ID的GroupBy分组中是否存在;若不存在,则添加该timestamp的记录(value1设为NaN,其他字段沿用对应ID的属性)。

原实现代码如下:

for indx, single_date in enumerate(df.timestamp):
    #print(single_date)
    if df.timestamp[indx] not in df.groupby(['ID'],as_index=False):
        df2 = pd.DataFrame([[df.ID[indx],df.timestamp[indx],np.nan,df.gender[indx],df.age[indx]]],
                           columns=['ID', 'timestamp', 'value1', 'gender', 'age'])
        #print(df2)
        df2['timestamp'] = pd.to_datetime(df2['timestamp'])
        new_ckd = df.groupby(['ID']).apply(lambda y: pd.concat([y, df2]))
new_ckd['timestamp'] = pd.to_datetime(new_ckd['timestamp'])
new_ckd = new_ckd.sort_values(by=['timestamp'], ascending=True).reset_index(drop=True)
#print(new_ckd)
    #print(df.ID[indx])
print(df.groupby(['ID'],as_index=False).timestamp.apply(print))
for indx, single_date in enumerate(df.timestamp):
    #print(df.timestamp[indx])
    if df.timestamp[indx] in df.groupby(['ID'],as_index=False).timestamp:
        print('a')

但针对GroupBy对象的if not in逻辑无法生效,如何修正以实现需求?

现有数据:

IDvalue1timestampgenderage
1502022-01-01 12:00:00m7
1802022-01-01 12:30:00m7
1652022-01-01 13:00:00m7
2652022-01-01 12:02:00f8
2832022-01-01 12:22:00f8
2632022-01-01 12:42:00f8

期望结果:

IDvalue1timestampgenderage
1502022-01-01 12:00:00m7
1NaN2022-01-01 12:02:00m7
1NaN2022-01-01 12:22:00m7
1802022-01-01 12:30:00m7
1NaN2022-01-01 12:42:00m7
1652022-01-01 13:00:00m7
2NaN2022-01-01 12:00:00f8
2652022-01-01 12:02:00f8
2832022-01-01 12:22:00f8
2NaN2022-01-01 12:30:00f8
2632022-01-01 12:42:00f8
2NaN2022-01-01 13:00:00f8
问题分析

原代码的核心错误是直接将timestamp与groupby(['ID'])对象做成员判断——GroupBy对象是分组容器,不是该分组下的timestamp集合,自然无法正确判断。此外,原代码循环拼接的逻辑会重复添加数据,效率极低且逻辑混乱。

正确思路:

  1. 统一转换timestamp为datetime类型,避免字符串匹配问题
  2. 获取所有唯一的timestamp值作为全局时间基准
  3. 为每个ID生成包含所有全局timestamp的组合,再与原数据左连接补全缺失记录
  4. 确保每个ID的非数值字段(gender、age)沿用该ID的固定属性
解决方案代码
import pandas as pd
import numpy as np

# 加载现有数据
data = {
    'ID': [1,1,1,2,2,2],
    'value1': [50,80,65,65,83,63],
    'timestamp': ['2022-01-01 12:00:00','2022-01-01 12:30:00','2022-01-01 13:00:00',
                  '2022-01-01 12:02:00','2022-01-01 12:22:00','2022-01-01 12:42:00'],
    'gender': ['m','m','m','f','f','f'],
    'age': [7,7,7,8,8,8]
}
df = pd.DataFrame(data)

# 1. 转换timestamp为datetime类型
df['timestamp'] = pd.to_datetime(df['timestamp'])

# 2. 获取所有唯一的timestamp
all_timestamps = df['timestamp'].unique()

# 3. 获取每个ID的固定属性(gender、age)
id_attrs = df.groupby('ID')[['gender', 'age']].first().reset_index()

# 4. 生成ID与所有timestamp的笛卡尔积
full_index = id_attrs.merge(pd.DataFrame({'timestamp': all_timestamps}), how='cross')

# 5. 左连接原数据,补全value1,缺失值自动为NaN
result = full_index.merge(df, on=['ID', 'timestamp'], how='left')

# 6. 整理列顺序并排序
result = result[['ID', 'value1', 'timestamp', 'gender', 'age']].sort_values(by=['ID', 'timestamp']).reset_index(drop=True)

print(result)
代码说明
  • 转换时间类型:确保时间匹配基于datetime对象,避免字符串格式不一致导致的匹配失败
  • 生成全时间组合:通过merge(how='cross')快速生成每个ID与所有全局timestamp的组合,这是补全缺失记录的核心
  • 左连接补全数据:全组合表与原数据左连接,存在的记录保留value1,缺失的自动填充NaN
  • 提取固定属性:通过groupby('ID').first()获取每个ID的gender和age,确保补全记录沿用正确属性

运行后即可得到与期望结果完全一致的DataFrame。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:55:00