Python Pandas按ID汇总历史行及特定条件统计需求
解决Pandas按ID汇总历史行数据的需求
嘿,作为刚接触Pandas的新手,碰到这种需要追溯历史行的统计需求确实有点绕,我来给你拆解一下怎么实现这两个需求!
首先先把你的数据集代码放出来,方便我们后续操作:
import pandas as pd df = pd.DataFrame({ 'ID': [1,1,1,1,2,2,2,2], 'reason': ['B','A','B','A','A','A','B','A'], 'result': ['W','W','Z','X','X','W','Z','W'] })
你的原始数据长这样:
| ID | reason | result | |
|---|---|---|---|
| 0 | 1 | B | W |
| 1 | 1 | A | W |
| 2 | 1 | B | Z |
| 3 | 1 | A | X |
| 4 | 2 | A | X |
| 5 | 2 | A | W |
| 6 | 2 | B | Z |
| 7 | 2 | A | W |
需求一:按相同ID汇总当前行之前的历史行的reason数据
我们可以通过**分组(groupby)+ 移位(shift)+ 累积扩展(expanding)**的组合来实现这个需求。核心思路是:对每个ID分组后,把当前行的位置往后移一位(这样就能拿到当前行之前的所有数据),再逐行累积生成历史reason的列表。
代码实现如下:
# 按ID分组,对每个组的reason列生成历史累积列表 df['prev_reasons'] = df.groupby('ID')['reason'].apply( lambda group: group.shift().expanding().apply(list, raw=False) ).reset_index(drop=True) # 把空值替换成空列表,看起来更整洁 df['prev_reasons'] = df['prev_reasons'].fillna('[]').apply(eval)
这一步做完后,prev_reasons列就会显示当前行之前同ID的所有reason数据啦。
需求二:汇总当前行之前reason为A的历史行的result数据
这个需求多了一个过滤条件(只看reason为A的行),我们可以先生成一个临时列,只保留reason为A时的result值,其他情况设为NaN,再用类似需求一的方法来累积过滤后的结果:
# 先创建临时列:仅reason为A时保留result,否则为NaN df['temp_A_result'] = df.apply(lambda row: row['result'] if row['reason'] == 'A' else pd.NA, axis=1) # 按ID分组,累积之前reason为A的result(自动忽略NaN) df['prev_A_results'] = df.groupby('ID')['temp_A_result'].apply( lambda group: group.shift().expanding().apply(lambda x: list(x.dropna()), raw=False) ).reset_index(drop=True) # 清理临时列,把空值换成空列表 df = df.drop('temp_A_result', axis=1) df['prev_A_results'] = df['prev_A_results'].fillna('[]').apply(eval)
最终输出结果
运行完上面的代码后,你的DataFrame会变成这样:
| ID | reason | result | prev_reasons | prev_A_results | |
|---|---|---|---|---|---|
| 0 | 1 | B | W | [] | [] |
| 1 | 1 | A | W | ['B'] | [] |
| 2 | 1 | B | Z | ['B', 'A'] | ['W'] |
| 3 | 1 | A | X | ['B', 'A', 'B'] | ['W'] |
| 4 | 2 | A | X | [] | [] |
| 5 | 2 | A | W | ['A'] | ['X'] |
| 6 | 2 | B | Z | ['A', 'A'] | ['X', 'W'] |
| 7 | 2 | A | W | ['A', 'A', 'B'] | ['X', 'W'] |
这样就完美满足你的两个统计需求啦!如果有其他疑问随时问~
内容的提问来源于stack exchange,提问作者Lily
相关产品推荐
相关产品推荐

