如何计算每列中的唯一重复值

How to count the unique duplicate values in each column

我们有以下数据框,

df = pd.DataFrame(data = {'A': [1,2,3,3,2,4,5,3],
                     'B': [9,6,7,9,2,5,3,3],
                     'C': [4,4,4,5,9,3,2,1]})
df

我想创建一个新的数据框,其中每个列名都将显示重复项的数量。

例如。 'B',有两个重复的值(9 和 3),我想打印 2 等

选项 1

如果我们需要计算重复值的个数

import pandas as pd

df = pd.DataFrame(data = {'A': [1,2,3,3,2,4,5,3],
                     'B': [9,6,7,9,2,5,3,3],
                     'C': [4,4,4,5,9,3,2,1]})

df1 = df.apply(lambda x:sum(x.duplicated()))
print(df1)

打印:

A    3
B    2
C    2
dtype: int64

选项 2

如果我们需要计算重复值的数量

df1 = df.agg(lambda x: sum(x.value_counts() > 1)) # or df1 = df.apply(lambda x: sum(x.value_counts() > 1))
print(df1)

打印:

A    2
B    2
C    1
dtype: int64

选项 2.1

详细

df1 = df.apply(lambda x: ' '.join([f'[val = {i}, cnt = {v}]' for i, v in x.value_counts().iteritems() if v > 1]))
print(df1)

打印:

A    [val = 3, cnt = 3] [val = 2, cnt = 2]
B    [val = 9, cnt = 2] [val = 3, cnt = 2]
C                       [val = 4, cnt = 3]
dtype: object

如果你想每个元素重复计数,你可以使用这个:

import pandas as pd
from collections import Counter

df = pd.DataFrame(data = {'A': [1,2,3,3,2,4,5,3],
                     'B': [9,6,7,9,2,5,3,3],
                     'C': [4,4,4,5,9,3,2,1]})
def cnt(x):
    return {k:v for k,v in x.items() if v>1}
        

df.apply(lambda x : cnt(Counter(x)))

输出:

A    {2: 2, 3: 3}
B    {9: 2, 3: 2}
C          {4: 3}
dtype: object

您可以使用 collections.Counteritertools.takewhile:

from collections import Counter
from itertools import takewhile
df.apply(lambda c: len(list(takewhile(lambda x: x[1]>1, Counter(c).most_common()))))

输出:

A    2
B    2
C    1

如果你想输出数据帧,添加.to_frame(name='n_duplicates'): 输出:

   n_duplicates
A             2
B             2
C             1

工作原理

对于每一列,Counter 获取每个元素的计数,然后 most_common returns 最常见的优先。

takewhile 迭代此输入并在有一个元素低于阈值(此处为 1)时立即停止。

最后,我们得到这个输出的长度,它对应于重复组的数量。

  • 这可以通过获取值计数大于 1 的 pandas.Series.value_counts for each column, and then get the pandas.Series.sum 来完成
    • vc[vc.gt(1)] 创建一个带有计数的 pandas.Series,对于列中的每个值,都大于 1。
  • 我们可以从%%timeit 5列1M行的比较中看出,使用矢量化方法的.apply以及for-loopdict-comprehension更快比使用 .apply 和内置 python sum(...).

.apply.value_counts.sum

  • col.value_counts().gt(1) 创建一个 Boolean 系列
    • True 计算为 1,False 计算为 0,因此 .sum() 产生正确的结果。
dupe_count = df.agg(lambda col: col.value_counts().gt(1).sum())

A    2
B    2
C    1
dtype: int64

for-loop

  • 通常不建议遍历数据框,尤其是按行。但是,我们正在遍历列,然后应用向量化函数,这等同于 .apply.
  • 的情况
def col_vc(df):
    dupe_count = dict()
    for col in df.columns:
        dupe_count[col] = df[col].value_counts().gt(1).sum()
    return dupe_count


col_vc(df)

[result]:
{'A': 2, 'B': 2, 'C': 1}
  • 相当于一行dict-comprehension
dupe_count = {col: df[col].value_counts().gt(1).sum() for col in df.columns}

[result]:
{'A': 2, 'B': 2, 'C': 1}

# to a dataframe if desired
dupe_count = pd.DataFrame.from_dict(dupe_count, orient='index')

   0
A  2
B  2
C  1

%%timeit比较

import pandas as pd
import numpy as np

# sample data 5 columns by 1M rows
np.random.seed(365)
rows = 1000000
data = {'a': np.random.randint(0, 10000, size=(rows)),
        'b': np.random.randint(15, 25000, size=(rows)),
        'c': np.random.randint(30, 40000, size=(rows)),
        'd': np.random.randint(450, 550000, size=(rows)),
        'e': np.random.randint(6000, 70000, size=(rows))}
df = pd.DataFrame(data)
  • .apply.value_counts.sum
%%timeit
df.agg(lambda x: x.value_counts().gt(1).sum())
[out]:
112 ms ± 1.67 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
  • dict-comprehension
%%timeit
{col: df[col].value_counts().gt(1).sum() for col in df.columns}
[out]:
111 ms ± 983 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
  • for-loop
%%timeit
col_vc(df)
[out]:
115 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
df.agg(lambda x: sum(x.value_counts() > 1))
[out]:
194 ms ± 17.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)