Python Pandas:根据出现次数删除条目

sas*_*llo 22 python numpy python-2.7 pandas

我正在尝试从数据框中删除少于100次的条目.数据框data如下所示:

pid   tag
1     23    
1     45
1     62
2     24
2     45
3     34
3     25
3     62
Run Code Online (Sandbox Code Playgroud)

现在我计算这样的标记出现次数:

bytag = data.groupby('tag').aggregate(np.count_nonzero)
Run Code Online (Sandbox Code Playgroud)

但后来我无法弄清楚如何删除那些数量较少的条目......

And*_*den 26

在0.12中新增,groupby对象有一个filter方法,允许您执行以下类型的操作:

In [11]: g = data.groupby('tag')

In [12]: g.filter(lambda x: len(x) > 1)  # pandas 0.13.1
Out[12]:
   pid  tag
1    1   45
2    1   62
4    2   45
7    3   62
Run Code Online (Sandbox Code Playgroud)

函数(过滤器的第一个参数)应用于每个组(子帧),结果包括属于评估为True的组的原始DataFrame的元素.

注意:在0.12中,排序与原始DataFrame中的顺序不同,这在0.13+中已修复:

In [21]: g.filter(lambda x: len(x) > 1)  # pandas 0.12
Out[21]: 
   pid  tag
1    1   45
4    2   45
2    1   62
7    3   62
Run Code Online (Sandbox Code Playgroud)

  • 感谢回到这个问题来传播过滤器的福音.重新排序是我应该包含在文档中的已知问题.如果设置``dropna = False``,则*维持*.如果不是,则可以对组进行洗牌.度假他们会花费时间,所以我把它留给了用户,这是一个值得商榷的选择. (3认同)

unu*_*tbu 23

编辑:感谢@WesMcKinney以更直接的方式展示:

data[data.groupby('tag').pid.transform(len) > 1]
Run Code Online (Sandbox Code Playgroud)
import pandas
import numpy as np
data = pandas.DataFrame(
    {'pid' : [1,1,1,2,2,3,3,3],
     'tag' : [23,45,62,24,45,34,25,62],
     })

bytag = data.groupby('tag').aggregate(np.count_nonzero)
tags = bytag[bytag.pid >= 2].index
print(data[data['tag'].isin(tags)])
Run Code Online (Sandbox Code Playgroud)

产量

   pid  tag
1    1   45
2    1   62
4    2   45
7    3   62
Run Code Online (Sandbox Code Playgroud)

  • 一个可爱的单行:data [data.groupby('tag').pid.transform(len)> 1] (12认同)
  • 我们现在有了[filter](http://pandas.pydata.org/pandas-docs/dev/groupby.html#filtration)方法. (3认同)

zbi*_*nsd 5

以下是此处发布的几个解决方案的一些运行时间,以及一个没有(使用value_counts())比其他解决方案快得多的解决方案:

创建数据:

import pandas as pd
import numpy as np

# Generate some 'users'
np.random.seed(42)
df = pd.DataFrame({'uid': np.random.randint(0, 500, 500)})

# Prove that some entries are 1
print "{:,} users only occur once in dataset".format(sum(df.uid.value_counts() == 1))
Run Code Online (Sandbox Code Playgroud)

输出:

171 users only occur once in dataset

使用几种不同的方法来删除仅一个条目的用户。这些在 Jupyter Notebook 的不同单元中运行:

%%timeit
df.groupby(by='uid').filter(lambda x: len(x) > 1)

%%timeit
df[df.groupby('uid').uid.transform(len) > 1]

%%timeit
vc = df.uid.value_counts()
df[df.uid.isin(vc.index[vc.values > 1])].uid.value_counts()
Run Code Online (Sandbox Code Playgroud)

这些给出了以下输出:

10 loops, best of 3: 46.2 ms per loop
10 loops, best of 3: 30.1 ms per loop
1000 loops, best of 3: 1.27 ms per loop
Run Code Online (Sandbox Code Playgroud)

  • 这绝对应该是公认的答案。使用 value_counts() 的一个比其他两个快 * 快得多,特别是对于具有大量组的数据集 (2认同)