如何用Pandas基于其他列组合捕获指定列的值变化?
问题描述
假设存在如下DataFrame(df):
id | date | type 1 | 2023-03-01T10:00:00Z | A 1 | 2023-03-01T12:00:00Z | A 1 | 2023-03-05T09:09:00Z | D 1 | 2023-03-02T12:00:00Z | B 1 | 2023-03-02T19:00:00Z | C 1 | 2023-03-03T22:00:00Z | B 1 | 2023-03-04T12:00:00Z | C 1 | 2023-03-05T08:00:00Z | C 1 | 2023-03-04T17:00:00Z | C 2 | 2023-02-01T12:00:00Z | A 2 | 2023-02-03T10:00:01Z | A 2 | 2023-02-03T11:00:00Z | A 2 | 2023-02-02T13:13:13Z | A
按date排序后的结果(供参考):
id | date | type 1 | 2023-03-01T10:00:00Z | A 1 | 2023-03-01T12:00:00Z | A 1 | 2023-03-02T12:00:00Z | B 1 | 2023-03-02T19:00:00Z | C 1 | 2023-03-03T22:00:00Z | B 1 | 2023-03-04T12:00:00Z | C 1 | 2023-03-04T17:00:00Z | C 1 | 2023-03-05T08:00:00Z | C 1 | 2023-03-05T09:09:00Z | D 2 | 2023-02-01T12:00:00Z | A 2 | 2023-02-02T11:00:00Z | A 2 | 2023-02-02T13:13:13Z | A 2 | 2023-02-03T12:00:00Z | A
注意:对于(id, date)的组合,不会出现重复的type值
最终目标DataFrame如下:
id | old_type | new_type | change_date 1 | A | B | 2023-03-02T12:00:00Z 1 | B | C | 2023-03-02T19:00:00Z 1 | C | B | 2023-03-03T22:00:00Z 1 | B | C | 2023-03-04T12:00:00Z 1 | C | D | 2023-03-05T09:09:00Z
由于id为2的记录在不同日期间type无变化,因此不会出现在结果中。需要通过Pandas实现上述转换。
解决方案
可以通过以下步骤实现需求:
- 按id和date排序,确保数据按用户和时间顺序排列
- 去除同一id下连续重复的type记录,保留每个type变化的起始记录
- 通过移位操作生成新旧type的对应关系
- 过滤无变化的记录,整理结果列名
具体代码如下:
import pandas as pd # 1. 按id和date排序 df_sorted = df.sort_values(['id', 'date'], ignore_index=True) # 2. 移除同一id下连续重复的type记录 df_dedup = df_sorted[df_sorted['type'] != df_sorted.groupby('id')['type'].shift()] # 3. 生成old_type、new_type和change_date字段 df_result = df_dedup.assign( old_type=df_dedup.groupby('id')['type'].shift(), new_type=df_dedup['type'], change_date=df_dedup['date'] ) # 4. 过滤无前置type的记录,并整理列顺序 df_result = df_result.dropna(subset=['old_type'])[['id', 'old_type', 'new_type', 'change_date']] # 重置索引(可选) df_result = df_result.reset_index(drop=True)
代码说明:
- 排序:
sort_values(['id', 'date'])保证同一用户的记录按时间先后排列,确保后续移位操作的正确性。 - 去重连续重复type:通过
groupby('id')['type'].shift()获取同一用户的上一条type,对比当前type,仅保留不同的行,去掉同一type的连续重复记录(比如id=1的两条A记录只保留第一条)。 - 生成新旧type:再次对每个用户的type移位,移位结果即为当前type的上一个类型(
old_type),当前type为new_type,当前date就是变化发生的时间。 - 过滤无效行:每个用户的第一条记录没有上一个type,用
dropna去掉,剩下的就是所有type变化的记录。
执行后即可得到目标DataFrame。
内容的提问来源于stack exchange,提问作者coder
相关产品推荐
相关产品推荐

