如何在Python中去除重复行并保留所有列的有效值
问题描述
给定如下Pandas DataFrame:
import pandas as pd from pandas import Timestamp import numpy as np df = pd.DataFrame({ 'Date': {0: Timestamp('2020-01-02 00:00:00'), 1: Timestamp('2020-01-02 00:00:00'), 2: Timestamp('2020-01-03 00:00:00'), 3: Timestamp('2020-01-03 00:00:00'), 4: Timestamp('2020-01-05 00:00:00'), 5: Timestamp('2020-01-05 00:00:00'), 6: Timestamp('2020-01-07 00:00:00')}, 'ID': {0: 245, 1: 245, 2: 245, 3: 245, 4: 472, 5: 472, 6: 472}, 'Colour': {0: 'Blue', 1: 'Blue', 2: 'Blue', 3: 'Green', 4: 'Red', 5: 'Red', 6: 'Red'}, 'ColourCode': {0: 'Bl', 1: np.nan, 2: 'Bl', 3: np.nan, 4: 'Re', 5: np.nan, 6: 'Re'}, 'Item': {0: 'Apple', 1: 'Apple', 2: 'Orange', 3: 'Apple', 4: 'Grape', 5: 'Grape', 6: 'Banana'}, 'ItemCode': {0: np.nan, 1: 'Ap', 2: np.nan, 3: 'Ap', 4: np.nan, 5: 'Gr', 6: np.nan} })
原始DataFrame表格展示:
| Date | ID | Colour | ColourCode | Item | ItemCode | |
|---|---|---|---|---|---|---|
| 0 | 2020-01-02 | 245 | Blue | Bl | Apple | NaN |
| 1 | 2020-01-02 | 245 | Blue | NaN | Apple | Ap |
| 2 | 2020-01-03 | 245 | Blue | Bl | Orange | NaN |
| 3 | 2020-01-03 | 245 | Green | NaN | Apple | Ap |
| 4 | 2020-01-05 | 472 | Red | Re | Grape | NaN |
| 5 | 2020-01-05 | 472 | Red | NaN | Grape | Gr |
| 6 | 2020-01-07 | 472 | Red | Re | Banana | NaN |
需求说明
当*Date*、*ID*、*Colour*、*Item*四列值完全相同时,判定为重复行。需要保留一行,且该行需合并重复组内*ColourCode*和*ItemCode*的有效值(即非NaN值)。
预期结果
| | Date | ID | Colour | ColourCode | Item | ItemCode | |---:|:-----------|-----:|:---------|:-------------|:-------|:-----------| | 0 | 2020-01-02 | 245 | Blue | Bl | Apple | Ap | | 1 | 2020-01-03 | 245 | Blue | Bl | Orange | NaN | | 2 | 2020-01-03 | 245 | Green | NaN | Apple | Ap | | 3 | 2020-01-05 | 472 | Red | Re | Grape | Gr | | 4 | 2020-01-07 | 472 | Red | Re | Banana | NaN |
解决方案
可以通过Pandas的groupby结合聚合方法实现,核心思路是按指定四列分组,提取每组内ColourCode和ItemCode的有效值。
方法一:使用groupby + first()
first()方法会在每组中从前往后取第一个非NaN值,正好匹配需求:
result = df.groupby(['Date', 'ID', 'Colour', 'Item'], as_index=False).first()
方法二:自定义聚合函数(灵活适配复杂场景)
如果需要针对不同列单独定义取值逻辑,可使用agg():
result = df.groupby(['Date', 'ID', 'Colour', 'Item'], as_index=False).agg( ColourCode=('ColourCode', lambda x: x.dropna().iloc[0] if not x.dropna().empty else np.nan), ItemCode=('ItemCode', lambda x: x.dropna().iloc[0] if not x.dropna().empty else np.nan) )
这种方式能精准控制每列的取值规则,适合更复杂的数据处理场景。
验证结果
执行上述任意一种方法后,得到的result与预期结果完全一致。
内容的提问来源于stack exchange,提问作者Shichimi
相关产品推荐
相关产品推荐

