根据多数规则删除重复项

时间:2018-05-15 17:37:21

标签: python pandas dataframe duplicates

我有一个看起来像这样的表:

A  B
1  cat
1  cat
1  dog
2  illama
2  alpaca
3  donkey

使用 A 作为密钥,我想删除重复项,以便该数据框成为:

A  B
1  cat
3  donkey

1 重复三次,值 cat 发生的次数最多,因此会被记录。 2 没有多数,所以它被认为是含糊不清的并且完全删除了。 3 仍然存在,因为它没有重复。

3 个答案:

答案 0 :(得分:7)

groupby + pd.Series.mode

这是使用pd.Series.mode的两步解决方案:

# find the mode for each group
i = df.groupby('A').B.apply(pd.Series.mode).reset_index(level=1, drop=True)
# filter out groups which have more than one mode—ambiguous groups
j = i[i.groupby(level=0).transform('count') == 1].reset_index()

print(j)

   A       B
0  1     cat
1  3  donkey

groupby + <自定义功能>

或者,定义一个计算模式的自定义函数,并使用apply调用它。过滤逻辑包含在函数中。

def foo(x):
    m = pd.Series.mode(x)
    if len(m) == 1: 
        return m

df.groupby('A').B.apply(foo).reset_index(level=1, drop=True).reset_index()

   A       B
0  1     cat
1  3  donkey

答案 1 :(得分:3)

您可以使用statistics.mode,如果不存在唯一模式,则会StatisticsError

from statistics import mode, StatisticsError

def moder(x):
    try:
        return mode(x)
    except StatisticsError:
        return None

res = df.groupby('A')['B'].apply(moder)\
        .dropna().reset_index()

print(res)

   A       B
0  1     cat
1  3  donkey

效果基准

尽管所有3种方法都适合您的任务,但它们的性能略有不同。

基准测试结果:

df = pd.concat([df]*10000)

%timeit jpp(df)  # 18.3 ms ± 414 µs per loop
%timeit cs1(df)  # 28.1 ms ± 558 µs per loop
%timeit cs2(df)  # 24.5 ms ± 595 µs per loop

基准代码:

from statistics import mode, StatisticsError

def moder(x):
    try:
        return mode(x)
    except StatisticsError:
        return None

def foo(x):
    m = pd.Series.mode(x)
    if len(m) == 1: 
        return m

def jpp(df):
    return df.groupby('A')['B'].apply(moder)\
             .dropna().reset_index()

def cs1(df):
    i = df.groupby('A').B.apply(pd.Series.mode).reset_index(level=1, drop=True)
    return i[i.groupby(level=0).transform('count') == 1].reset_index()

def cs2(df):
    return df.groupby('A').B.apply(foo).reset_index(level=1, drop=True).reset_index()

答案 2 :(得分:3)

如何使用value_countsrank

df.groupby('A')['B'].apply(lambda x: x.value_counts().rank(ascending=False)).eq(1)[lambda x: x].reset_index()

输出:

   A level_1     B
0  1     cat  True
1  3  donkey  True

使用排名方法=&#39;平均值&#39;作为选民获得多数&#34;来自value_count的结果。