删除*几乎*重复的观察结果-Python
我试图删除熊猫数据框架中的一些观察结果,其中相似性几乎为100%,但不完全相同。见下面的框架: 注意“约翰”、“玛丽”和“卫斯理”有着几乎相同的观察结果,但有一列是不同的。真实数据集有15列和215000多个观测值。在我可以目测验证的所有案例中,相似性都是一样的:在15列中,另一列每次最多匹配14列。出于项目的目的,我决定删除重复的观察结果(并将它们存储到另一个数据框中,以防我的老板要求查看它们)删除*几乎*重复的观察结果-Python,python,pandas,duplicates,Python,Pandas,Duplicates,我试图删除熊猫数据框架中的一些观察结果,其中相似性几乎为100%,但不完全相同。见下面的框架: 注意“约翰”、“玛丽”和“卫斯理”有着几乎相同的观察结果,但有一列是不同的。真实数据集有15列和215000多个观测值。在我可以目测验证的所有案例中,相似性都是一样的:在15列中,另一列每次最多匹配14列。出于项目的目的,我决定删除重复的观察结果(并将它们存储到另一个数据框中,以防我的老板要求查看它们) 我显然想到过删除重复项(keep='something'),但那是行不通的,因为观察结果并不完全
我显然想到过删除重复项(keep='something'),但那是行不通的,因为观察结果并不完全相同。有没有人遇到过这样的问题?有什么补救办法吗?简单的列子集循环怎么样:
import pandas as pd
df = pd.DataFrame(
[
['John', 45, 85000, 'DC'],
['Netcha', 25, 48000, 'NYC'],
['Mary', 45, 85000, 'DC'],
['Wesley', 36, 72500, 'LA'],
['Porter', 22, 98750, 'Seattle'],
['John', 45, 105500, 'DC'],
['Mary', 28, 85000, 'DC'],
['Wesley', 36, 72500, 'Boston'],
],
columns=['Name', 'Age', 'Salary', 'City'])
cols = df.columns.tolist()
cols.remove('Name')
for col in cols:
observed_cols = df.drop(col, axis=1).columns.tolist()
df.drop_duplicates(observed_cols, keep='first', inplace=True)
print(df)
返回:
Name Age Salary City
0 John 45 85000 DC
1 Netcha 25 48000 NYC
2 Mary 45 85000 DC
3 Wesley 36 72500 LA
4 Porter 22 98750 Seattle
这可以表示为所有记录之间的成对汉明距离计算,将低于某个阈值的后续记录对分离出来。幸运的是,numpy/scipy/sklearn已经完成了这项繁重的工作。我包含了两个产生相同输出的函数——一个是完全矢量化的(但消耗O(N^2)内存),另一个是消耗O(N)内存但仅沿单个维度矢量化的。在您的范围内,您几乎肯定不想要完全矢量化的版本-它可能会产生OOM错误。在这两种情况下,基本算法如下:
- 将每个特征值编码为整数值(感谢sklearn!)
- 对于所有行对,计算汉明距离(不同值之和)
- 如果在
或低于汉明距离,则丢弃后者,直到没有任何行保持在该阈值以下阈值处发现两行
arr = np.array("abcdefgh")
df = pd.DataFrame(np.random.choice(arr, (40000, 15))
# (df_deduped, df_dupes) = dedupe_partially_vectorized(df)
如果您可以避免进行所有成对比较,例如按名称分组,那么将显著提高性能
乐趣旁白/方法问题
您可能会注意到,您可以获得有趣的“汉明链”(我不知道这是否是一个术语),其中非常不同的记录由一个编辑差异记录链连接:
df_bad_news = pd.DataFrame(
[
["john", "doe", "m", 88],
["jon", "doe", "m", 88],
["jan", "doe", "m", 88],
["jane", "doe", "m", 88],
["jane", "doe", "m", 12],
],
columns=["first", "last", "s", "age"],
)
(df_deduped, df_dupes) = dedupe(df)
# df_deduped
# first last s age
# 0 john doe m 88
# df_dupes
# first last s age
# 1 jon doe m 88
# 2 jan doe m 88
# 3 jane doe m 88
# 4 jane doe m 12
如果有一个可以分组的字段(注释中提到,name
应该是相同的),那么性能将大大提高。这里两两计算在内存中为n^2。可以根据需要用一些时间效率换取内存效率。python库可以满足您的需要
看看这个答案:
这不是我的专业领域,但我有一些想法。我会考虑有一些相同的门限数。比如,如果你有15列,你的阈值是12,那么如果12-15个单元格匹配,你会认为它是一个复制品。但是如果11个或更少的匹配,那么你不认为它是一个复制品。或者诸如此类的事情,可能您实际上想要完全忽略某些列以进行重复检查。比如在你的例子中,也许你会忽略薪水。但这取决于你想要它的设计方式。这些看起来有用吗?这能回答你的问题吗@戴维奥科。有些相似,但完全不同的相似性度量。我想说,这已经足够不同了。您是否保证对于所有几乎重复的条目,至少有一列是相同的?如果不同记录中的相同名称因年龄不同而不同,您是否需要一个阈值来将记录标记为唯一的。例如,22岁的约翰可能与68岁的约翰不同。太好了!非常优雅的解决方案。也许您可以在每个组中按名称分组并进行重复数据消除。这确实非常漂亮!!谢谢@anon01
arr = np.array("abcdefgh")
df = pd.DataFrame(np.random.choice(arr, (40000, 15))
# (df_deduped, df_dupes) = dedupe_partially_vectorized(df)
df_bad_news = pd.DataFrame(
[
["john", "doe", "m", 88],
["jon", "doe", "m", 88],
["jan", "doe", "m", 88],
["jane", "doe", "m", 88],
["jane", "doe", "m", 12],
],
columns=["first", "last", "s", "age"],
)
(df_deduped, df_dupes) = dedupe(df)
# df_deduped
# first last s age
# 0 john doe m 88
# df_dupes
# first last s age
# 1 jon doe m 88
# 2 jan doe m 88
# 3 jane doe m 88
# 4 jane doe m 12