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

mor*_*rty 8 python duplicates dataframe pandas

请考虑以下数据帧

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
Run Code Online (Sandbox Code Playgroud)

我想删除与列有关的所有重复行'A' 'B'.我想删除有条目的NaN条目(我知道所有的dulicates都会有一个NaN和一个非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
Run Code Online (Sandbox Code Playgroud)

所有高效的单行都是最受欢迎的

cs9*_*s95 6

如果目标是仅删除NaN重复项,则需要稍微更复杂的解决方案.

首先,排序on A,BCol_1,因此NaNs被移动到每个组的底部.然后调用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
Run Code Online (Sandbox Code Playgroud)


cma*_*her 5

这是一个替代方案:

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
Run Code Online (Sandbox Code Playgroud)

这使用按位“非”运算符~来消除满足作为重复行的联合条件的行(该参数keep=False使该方法对所有非唯一行的结果都为True),并且至少包含一个null值。因此,表达式在哪里df[['A', 'B']].duplicated(keep=False)返回此Series:

# 0    False
# 1    False
# 2     True
# 3     True
# 4     True
# 5     True
# 6    False
# 7    False
# 8    False
Run Code Online (Sandbox Code Playgroud)

...表达式df.isnull().any(axis=1)返回该Series:

# 0     True
# 1    False
# 2    False
# 3     True
# 4    False
# 5     True
# 6    False
# 7     True
# 8     True
Run Code Online (Sandbox Code Playgroud)

...我们将它们都包装在括号中(在索引操作中使用多个表达式时,Pandas语法都需要),然后再次将它们包装在括号中这样我们就可以否定整个表达式(~( ... )例如),如下所示:

~((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
Run Code Online (Sandbox Code Playgroud)

您可以通过进一步使用逻辑运算符&|(或“或”运算符)来建立更复杂的条件。与SQL一样,根据需要用附加括号将条件分组。例如,使用基于逻辑“ 条件X条件Y都为真,或条件Z为真”的过滤器df[ ( (X) & (Y) ) | (Z) ]