Python:搜索从 pandas 数据帧列表中删除重复项的方法?

Python: searching way to remove duplicates from list of pandas dataframes?

我有一些包含 pandas 数据帧的列表。他们是从中删除重复项的一种方法。这里有一些示例代码:

import pandas as pd
import numpy as np

if __name__ == '__main__':
    data1 = {'row_1': [3, 2, 1, 0], 'row_2': ['a', 'b', 'c', 'd']}
    
    df1 = pd.DataFrame.from_dict(data1, orient='index', columns=['A', 'B', 'C', 'D'])
    data2 = {'col_1': [3, 2, 1, 0], 'col_2': ['a', 'b', 'c', 'd']}

    df2 = pd.DataFrame.from_dict(data2)
    df3 = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
                   columns=['a', 'b', 'c'])
    data = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)],

                dtype=[("a", "i4"), ("b", "i4"), ("c", "i4")])

    df4 = pd.DataFrame(data, columns=['c', 'a'])

    l_input = [df1, df2, df1, df3, df4, df4, df1, df3]
    # l_aim = [df1, df2, df3, df4]

应删除示例中的输入列表 l_input,结果应为 l_aim。

尝试 df.equals():

out = []
while l_input:
    d = l_input.pop()
    if any(d.equals(df) for df in l_input):
        continue
    out.append(d)

print(*out[::-1], sep="\n\n")

打印:

       A  B  C  D
row_1  3  2  1  0
row_2  a  b  c  d

   col_1 col_2
0      3     a
1      2     b
2      1     c
3      0     d

   a  b  c
0  1  2  3
1  4  5  6
2  7  8  9

   c  a
0  3  1
1  6  4
2  9  7

如果这些实际上是相同的对象(如您的示例所示),那么您可以使用它们的 ids:

out = list(dict((id(df), df) for df in l_input).values())

如果没有,您可以使用 equals:

输出:

[       A  B  C  D
 row_1  3  2  1  0
 row_2  a  b  c  d,
    col_1 col_2
 0      3     a
 1      2     b
 2      1     c
 3      0     d,
    a  b  c
 0  1  2  3
 1  4  5  6
 2  7  8  9,
    c  a
 0  3  1
 1  6  4
 2  9  7]

在线性时间内找到重复项的一种有效方法是计算数据帧的哈希值。用pythonhash函数是不行的,但是pandas里面有个辅助函数:pandas.util.hash_pandas_object.

该函数计算每行的哈希值,因此您需要聚合为单个值。 sum 可以使用,但可能会导致冲突。在这里,我选择了所有哈希的串联。如果你有巨大的数据帧,这可能会消耗大量内存(在这种情况下,可能会散列哈希列表)。

更新。 hashes的hash似乎比较理想,见答案末尾的第二个选项。

hashes = [pd.util.hash_pandas_object(d).astype(str).str.cat(sep='-')
          for d in l_input]

# identify duplicated per index
dups = pd.Series(hashes).duplicated()

输出:

0    False
1    False
2     True
3    False
4    False
5     True
6     True
7     True
dtype: bool

要过滤唯一数据帧:

out = [d for d,h in zip(l_input, dups) if h]

具有哈希的哈希的变体

我最初不确定计算散列列表的散列是否安全,但是this seems to be the case,所以下面的第二种方法应该是首选:

def df_hash(df):
    s = pd.util.hash_pandas_object(df)
    return hash(tuple(s))

hashes = [df_hash(d) for d in l_input]

dups = pd.Series(hashes).duplicated()

out = [d for d,h in zip(l_input, dups) if h]