如何有条件地从pandas数据帧中删除重复项

时间:2017-08-27 16:41:46

标签: python pandas dataframe duplicates

考虑以下数据框

import pandas as pd
df = pd.DataFrame({'A' : [1, 2, 3, 3, 4, 4, 5, 6, 7],
                   'B' : ['a','b','c','c','d','d','e','f','g'],
                   'Col_1' :[np.NaN, 'A','A', np.NaN, 'B', np.NaN, 'B', np.NaN, np.NaN],
                   'Col_2' :[2,2,3,3,3,3,4,4,5]})
df
Out[92]: 
    A  B Col_1  Col_2
 0  1  a   NaN      2
 1  2  b     A      2
 2  3  c     A      3
 3  3  c   NaN      3
 4  4  d     B      3
 5  4  d   NaN      3
 6  5  e     B      4
 7  6  f   NaN      4
 8  7  g   NaN      5

我想删除与列'A' 'B'有关的所有重复行。我想删除具有NaN条目的条目(我知道对于所有dulicates,将有NaN和not - NaN条目。最终结果应如下所示

    A  B Col_1  Col_2
 0  1  a   NaN      2
 1  2  b     A      2
 2  3  c     A      3
 4  4  d     B      3
 6  5  e     B      4
 7  6  f   NaN      4
 8  7  g   NaN      5

非常欢迎所有高效的单行

3 个答案:

答案 0 :(得分:6)

如果目标只是删除NaN重复项,则需要一个稍微复杂的解决方案。

首先,对ABCol_1进行排序,以便将NaN移到每个组的底部。然后使用df.drop_duplicates

致电keep=first
out = df.sort_values(['A', 'B', 'Col_1']).drop_duplicates(['A', 'B'], keep='first')
print(out)

   A  B Col_1  Col_2
0  1  a   NaN      2
1  2  b     A      2
2  3  c     A      3
4  4  d     B      3
6  5  e     B      4
7  6  f   NaN      4
8  7  g   NaN      5

答案 1 :(得分:4)

这是另一种选择:

df[~((df[['A', 'B']].duplicated(keep=False)) & (df.isnull().any(axis=1)))]
#    A  B Col_1  Col_2
# 0  1  a   NaN      2
# 1  2  b     A      2
# 2  3  c     A      3
# 4  4  d     B      3
# 6  5  e     B      4
# 7  6  f   NaN      4
# 8  7  g   NaN      5

这使用按位“not”运算符~来否定满足作为重复行的关节条件的行(参数keep=False导致方法对所有非唯一行计算为True )并包含至少一个空值。因此表达式df[['A', 'B']].duplicated(keep=False)返回此系列的位置:

# 0    False
# 1    False
# 2     True
# 3     True
# 4     True
# 5     True
# 6    False
# 7    False
# 8    False

...表达式df.isnull().any(axis=1)返回此系列:

# 0     True
# 1    False
# 2    False
# 3     True
# 4    False
# 5     True
# 6    False
# 7     True
# 8     True

...我们将两者括在括号中(每当在索引操作中使用多个表达式时都需要Pandas语法),然后将它们再次包含在括号 中,以便我们可以否定整个表达式(即{ {1}}),如下:

~( ... )

您可以通过进一步使用逻辑运算符~((df[['A','B']].duplicated(keep=False)) & (df.isnull().any(axis=1))) & (df['Col_2'] != 5) # 0 True # 1 True # 2 True # 3 False # 4 True # 5 False # 6 True # 7 True # 8 False &(“或”运算符)来构建更复杂的条件。与SQL一样,根据需要将条件与其他括号分组;例如,基于逻辑“两个条件X AND 条件Y 的过滤器为真,或条件Z 为真”与{{1} }。

答案 2 :(得分:1)

或者您可以使用first(),使用第一个,将返回第一个notnull值,因此原始输入的顺序并不重要。

df.groupby(['A','B']).first()

Out[180]: 
    Col_1  Col_2
A B             
1 a   NaN      2
2 b     A      2
3 c     A      3
4 d     B      3
5 e     B      4
6 f   NaN      4
7 g   NaN      5