python - 如果特定的其他列不为空(Pandas),如何删除重复项但保留行
问题描述
我有很多重复的记录——其中一些有银行账户。我想用银行账户保存记录。
基本上是这样的:
if there are two Tommy Joes:
keep the one with a bank account
我尝试使用下面的代码进行重复数据删除,但它保留了没有银行账户的重复数据。
df = pd.DataFrame({'firstname':['foo Bar','Bar Bar','Foo Bar','jim','john','mary','jim'],
'lastname':['Foo Bar','Bar','Foo Bar','ryan','con','sullivan','Ryan'],
'email':['Foo bar','Bar','Foo Bar','jim@com','john@com','mary@com','Jim@com'],
'bank':[np.nan,'abc','xyz',np.nan,'tge','vbc','dfg']})
df
firstname lastname email bank
0 foo Bar Foo Bar Foo bar NaN
1 Bar Bar Bar Bar abc
2 Foo Bar Foo Bar Foo Bar xyz
3 jim ryan jim@com NaN
4 john con john@com tge
5 mary sullivan mary@com vbc
6 jim Ryan Jim@com dfg
# get the index of unique values, based on firstname, lastname, email
# convert to lower and remove white space first
uniq_indx = (df.dropna(subset=['firstname', 'lastname', 'email'])
.applymap(lambda s:s.lower() if type(s) == str else s)
.applymap(lambda x: x.replace(" ", "") if type(x)==str else x)
.drop_duplicates(subset=['firstname', 'lastname', 'email'], keep='first')).index
# save unique records
dfiban_uniq = df.loc[uniq_indx]
dfiban_uniq
firstname lastname email bank
0 foo Bar Foo Bar Foo bar NaN # should not be here
1 Bar Bar Bar Bar abc
3 jim ryan jim@com NaN # should not be here
4 john con john@com tge
5 mary sullivan mary@com vbc
# I wanted these duplicates to appear in the result:
firstname lastname email bank
2 Foo Bar Foo Bar Foo Bar xyz
6 jim Ryan Jim@com dfg
您可以看到索引 0 和 3 被保留。这些拥有银行账户的客户的版本已被删除。我的预期结果是反过来。删除没有银行账户的骗子。
我曾考虑过先按银行账户进行排序,但我有这么多数据,我不确定如何“感知检查”它是否有效。
任何帮助表示赞赏。
这里有一些类似的问题,但它们似乎都有可以排序的值,例如年龄等。这些散列的银行帐号非常混乱
编辑:
在我的真实数据集上尝试答案的一些结果。
@Erfan 的方法按子集 + 银行对值进行排序
重复数据删除后剩余 58594 条记录:
subset = ['firstname', 'lastname']
df[subset] = df[subset].apply(lambda x: x.str.lower())
df[subset] = df[subset].apply(lambda x: x.replace(" ", ""))
df.sort_values(subset + ['bank'], inplace=True)
df.drop_duplicates(subset, inplace=True)
print(df.shape[0])
58594
@Adam.Er8 使用按银行排序值回答。重复数据删除后剩余 59170 条记录:
uniq_indx = (df.sort_values(by="bank", na_position='last').dropna(subset=['firstname', 'lastname', 'email'])
.applymap(lambda s: s.lower() if type(s) == str else s)
.applymap(lambda x: x.replace(" ", "") if type(x) == str else x)
.drop_duplicates(subset=['firstname', 'lastname', 'email'], keep='first')).index
df.loc[uniq_indx].shape[0]
59170
不知道为什么会出现差异,但两者都足够相似。
解决方案
bank
您应该按列对值进行排序,使用na_position='last'
(因此.drop_duplicates(..., keep='first')
将保留一个不是 na 的值)。
尝试这个:
import pandas as pd
import numpy as np
df = pd.DataFrame({'firstname': ['foo Bar', 'Bar Bar', 'Foo Bar'],
'lastname': ['Foo Bar', 'Bar', 'Foo Bar'],
'email': ['Foo bar', 'Bar', 'Foo Bar'],
'bank': [np.nan, 'abc', 'xyz']})
uniq_indx = (df.sort_values(by="bank", na_position='last').dropna(subset=['firstname', 'lastname', 'email'])
.applymap(lambda s: s.lower() if type(s) == str else s)
.applymap(lambda x: x.replace(" ", "") if type(x) == str else x)
.drop_duplicates(subset=['firstname', 'lastname', 'email'], keep='first')).index
# save unique records
dfiban_uniq = df.loc[uniq_indx]
print(dfiban_uniq)
输出:
bank email firstname lastname
1 abc Bar Bar Bar Bar
2 xyz Foo Bar Foo Bar Foo Bar
(这只是您.sort_values(by="bank", na_position='last')
在开头的原始代码uniq_indx = ...
)
推荐阅读
- swift - 使用 ScriptingBridge 在 macOS 中读取当前播放的曲目不起作用
- c++ - 我想使用 CMakeLists.txt 在我的代码中为 linux 和 windows 集成 ODBC,但它只在 windows 中工作
- highcharts - 将共享工具提示放置在堆叠列上方
- java - 当另一个类更新它时更新对象值
- apache-kafka - Spring Kafka/Spring Cloud Stream 如何保证涉及数据库和 Kafka 的事务性/原子性?
- java - Java中数组排序的问题
- javascript - Javascript 中不包括星期日和星期六
- react-native - 在 React-Native/Expo 移动应用程序上设置 Detox 时出错:“ReferenceError: element is not defined”
- react-native - 有没有清除Expo缓存的方法?
- python - 问题:如何将函数更改为python中的类