Pandas:填充行并去重,但保留不同值

1 投票
2 回答
68 浏览
提问于 2025-04-13 19:02

我会尽量用简单明了的例子来解释。

df_old

user, col1,col2,col3
a   ,  X  ,    ,
a   ,     ,  Y ,
a   ,     ,    , 6
b   ,  A  ,    ,
b   ,     ,  B , C
b   ,     ,  D ,

这个数据表是按照 user 排序的。我想填补空白并去掉重复的记录,所以对于用户 a,我希望最终的数据表中只保留一行。

我在处理像用户 b 这样的情况时遇到了困难。因为用户 b 在 col2 中有两个不同的值,所以我希望最终的数据表中能有两行不同的记录:

df_new

user, col1,col2,col3
a   ,  X  ,  Y , 6
b   ,  A  ,  B , C
b   ,  A  ,  D , C

请注意,我希望这些行是“一致”的,这样 B 和 C 就能保持在同一个索引位置。

非常感谢任何帮助!

2 个回答

2

你可以先用 ffill 方法填充缺失值,然后再用 dropna 方法去掉那些全是缺失值的行:

df.groupby('user', group_keys=False).apply(lambda g: g.ffill()).dropna(how='any')

输出结果:

  user col1 col2 col3
2    a    X    Y    6
4    b    A    B    C
5    b    A    D    C

另外,如果你不想填充缺失值,可以使用 groupby.transform 方法把非缺失值向上移动,然后再用 dropna 方法去掉那些全是缺失值的行:

out = (df.set_index('user')
         .groupby(level=0)
         .transform(lambda s: s.sort_values(key=lambda x: x.isna(),
                                            kind='stable').values)
         .dropna(how='all').reset_index()
      )

输出结果:

  user col1 col2 col3
0    a    X    Y    6
1    b    A    B    C
2    b  NaN    D  NaN

使用的输入数据:

df = pd.DataFrame({'user': ['a', 'a', 'a', 'b', 'b', 'b'],
                  'col1': ['X', None, None, 'A', None, None],
                  'col2': [None, 'Y', None, None, 'B', 'D'],
                  'col3': [None, None, '6', None, 'C', None]})
3

使用 GroupBy.transform 方法,可以通过 Series.maskSeries.duplicated 来处理重复的 NaN 值。这个过程是先按非 NaN 值排序,然后处理缺失值,最后在每个用户组中去掉重复项。

out = (df.set_index('user')
         .groupby('user')
         .transform(lambda x: x.mask(x.duplicated()).sort_values(key=pd.isna).ffill())
         .reset_index()
         .drop_duplicates(ignore_index=True)
         )
print (out)
  user col1 col2 col3
0    a    X    Y    6
1    b    A    B    C
2    b    A    D    C

编辑:如果需要每一行的缺失值,并且至少有一个非缺失值的话,可以省略 ffill,而是使用 DataFrame.dropna 方法,并设置 axis='all' 参数。

out = (df.set_index('user')
         .groupby('user')
         .transform(lambda x: x.mask(x.duplicated()).sort_values(key=pd.isna))
         .dropna(how='all')
         .reset_index()
         )
print (out)
  user col1 col2 col3
0    a    X    Y    6
1    b    A    B    C
2    b  NaN    D  NaN

撰写回答