合并Pandas DataFrame行时的列表顺序与列值NA问题修复咨询
问题描述
原始数据集:
| Name | Year | Attempt | Math | English | Science | Height | Rank |
|---|---|---|---|---|---|---|---|
| Peter | 2020 | 1 | 92 | 95 | 82 | 63 | Top 50 |
| Peter | 2021 | 2 | 93 | 94 | 86 | 63 | Top 50 |
| Andy | 2023 | 1 | 84 | 91 | 87 | 68 | 51-100 |
| Charles | 2019 | 1 | 87 | 89 | 82 | 67 | 101-150 |
| Charles | 2020 | 2 | 92 | 91 | 76 | 67 | 101-150 |
| Charles | 2021 | 3 | 94 | 92 | 90 | 67 | 101-150 |
| Charles | 2022 | 4 | 87 | 98 | 99 | 67 | 101-150 |
| Luke | 2023 | 1 | 76 | 98 | 99 | 80 | Unranked |
期望处理后格式:
| Name | Final Year | Attempt | Math | English | Science | Height | Rank |
|---|---|---|---|---|---|---|---|
| Peter | 2021 | [1, 2] | [92, 93] | [95, 94] | [82, 86] | 63 | Top 50 |
| Andy | 2023 | 1 | 84 | 91 | 87 | 68 | 51-100 |
| Charles | 2022 | [1, 2, 3, 4] | [87, 92, 94, 87] | [89, 91, 92, 98] | [82, 76, 90, 99] | 67 | 101-150 |
| Luke | 2023 | 1 | 76 | 98 | 99 | 80 | Unranked |
其中Height和Rank同一人员记录值一致,Final Year取该人员最新年份。
用户使用的代码:
df2 = (df.set_index('Name').groupby(level = 0).agg(list)) df2['Age'] = df2['Age'].apply(max) df2[['Height', 'Rank']] = df2[['Height', 'Rank']].apply(lambda x: x[0]) display(df2)
运行后遇到的问题:
- Attempt、Math、English等列的列表顺序反转
- Height和Rank列被填充为NA
问题分析
- 列表顺序反转:
groupby默认不保证保留原始数据的顺序,若未对数据按Year升序排序,聚合后的列表会打乱时间顺序。 - Height和Rank列出现NA:
- 原代码中
df2['Age']是笔误,实际应为Year列; df2[['Height', 'Rank']].apply(lambda x: x[0])的写法错误——该操作是对整个列(Series)取第一个元素,而非对每个单元格的列表取第一个值,导致赋值失败出现NA。
- 原代码中
修正后的代码
# 先按姓名和年份升序排序,确保聚合时列表顺序与时间一致 df_sorted = df.sort_values(by=['Name', 'Year']) # 按姓名分组,指定每列的聚合规则 df2 = df_sorted.groupby('Name').agg( Final_Year=('Year', 'max'), Attempt=('Attempt', list), Math=('Math', list), English=('English', list), Science=('Science', list), Height=('Height', 'first'), # 同一用户值相同,直接取第一个即可 Rank=('Rank', 'first') ).reset_index() # 可选:将只有单个元素的列表转为单个值,匹配期望格式 def flatten_single_list(x): return x[0] if isinstance(x, list) and len(x) == 1 else x # 对需要处理的列应用扁平化函数 cols_to_process = ['Attempt', 'Math', 'English', 'Science'] df2[cols_to_process] = df2[cols_to_process].applymap(flatten_single_list) display(df2)
代码说明
- 排序步骤:通过
sort_values确保每个用户的记录按年份从小到大排列,聚合后的列表顺序与时间顺序一致,解决反转问题。 - 分组聚合:明确指定各列的聚合逻辑,
Final_Year直接取Year的最大值;Height和Rank用first聚合,避免生成列表后再处理,直接得到单个有效值。 - 扁平化处理:将只有一个元素的列表转为单个值,完全匹配期望的输出格式,若不需要此效果可省略该步骤。
内容的提问来源于stack exchange,提问作者bangbanggggg
相关产品推荐
相关产品推荐

