删除*几乎*重复的观察结果-Python

删除*几乎*重复的观察结果-Python,python,pandas,duplicates,Python,Pandas,Duplicates,我试图删除熊猫数据框架中的一些观察结果,其中相似性几乎为100%,但不完全相同。见下面的框架: 注意“约翰”、“玛丽”和“卫斯理”有着几乎相同的观察结果,但有一列是不同的。真实数据集有15列和215000多个观测值。在我可以目测验证的所有案例中,相似性都是一样的:在15列中,另一列每次最多匹配14列。出于项目的目的,我决定删除重复的观察结果(并将它们存储到另一个数据框中,以防我的老板要求查看它们) 我显然想到过删除重复项(keep='something'),但那是行不通的,因为观察结果并不完全

我试图删除熊猫数据框架中的一些观察结果,其中相似性几乎为100%,但不完全相同。见下面的框架:

注意“约翰”、“玛丽”和“卫斯理”有着几乎相同的观察结果,但有一列是不同的。真实数据集有15列和215000多个观测值。在我可以目测验证的所有案例中,相似性都是一样的:在15列中,另一列每次最多匹配14列。出于项目的目的,我决定删除重复的观察结果(并将它们存储到另一个数据框中,以防我的老板要求查看它们)


我显然想到过删除重复项(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!)
  • 对于所有行对,计算汉明距离(不同值之和)
  • 如果在
    阈值处发现两行
    或低于汉明距离,则丢弃后者,直到没有任何行保持在该阈值以下
代码:

我已经在多达40k行的数据帧(如下所示)上对此进行了测试,它似乎有效(这两种方法给出了相同的结果),但可能需要几秒钟的时间。我还没有按你的规模试过,但速度可能很慢:

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