【问题标题】:Python Pandas: remove entries based on the number of occurrencesPython Pandas:根据出现次数删除条目
【发布时间】:2012-11-06 22:37:36
【问题描述】:

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

pid   tag
1     23    
1     45
1     62
2     24
2     45
3     34
3     25
3     62

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

bytag = data.groupby('tag').aggregate(np.count_nonzero)

但是我不知道如何删除那些计数低的条目...

【问题讨论】:

  • 作为@unutbu suggests,请考虑更改接受的答案(过滤方法更简单:))

标签: python numpy python-2.7 pandas


【解决方案1】:

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

函数(filter的第一个参数)被应用于每个组(子帧),结果包括原始DataFrame中属于评估为True的组的元素。

注意:in 0.12 the ordering is different than in the original 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

【讨论】:

  • 我想知道结果的顺序不是相同的顺序是故意的......
  • 感谢您回到这个问题来宣讲过滤器的福音。重新排序是一个已知问题,我应该将其包含在文档中。如果您设置dropna=False,则顺序保持。如果没有,组可能会被洗牌。使用它们会花费时间,所以我把它留给了用户,这是一个值得商榷的选择。
  • @DanAllan 此外,如果存在重复/无序索引,将它们按顺序放回可能并非易事。啊哈,目前可以:g.filter(lambda x: len(x) > 1, dropna=False).dropna()保持订单。
  • @DanAllan 哦,不,你不能......因为重新索引不适用于重复。所以过滤器不起作用。请注意,也不会变形。
  • @sashkello:请考虑将此作为接受的答案。它更简单,是前进的正确方法。
【解决方案2】:

编辑:感谢@WesMcKinney 展示了这种更直接的方式:

data[data.groupby('tag').pid.transform(len) > 1]

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)])

产量

   pid  tag
1    1   45
2    1   62
4    2   45
7    3   62

【讨论】:

  • 一个可爱的单行:data[data.groupby('tag').pid.transform(len) > 1]
  • 我们现在有了filter 方法。
  • 如果我有另一列显示“userid”怎么办。我只想选择那些数据,其中 pid 有超过 100 个条目,同时,uid 有超过 100 个条目。我试过 & only group by,但它似乎不起作用。 reviews_imp_pr = reviews_imp[(reviews_imp.groupby('author')['score'].count() > 50) & (reviews_imp.groupby('product')['score'].count() > 50) ]跨度>
【解决方案3】:

以下是此处发布的几个解决方案的一些运行时间,以及一个(使用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))

输出:

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()

这些给出了以下输出:

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

【讨论】:

  • 这绝对应该是公认的答案。使用 value_counts() 的一个比其他两个快很多,尤其是对于具有大量组的数据集
  • 最后一个方法在 30M 数据中相当快。谢谢。
【解决方案4】:
df = pd.DataFrame([(1, 2), (1, 3), (1, 4), (2, 1),(2,2,)], columns=['col1', 'col2'])

In [36]: df
Out[36]: 
   col1  col2
0     1     2
1     1     3
2     1     4
3     2     1
4     2     2

gp = df.groupby('col1').aggregate(np.count_nonzero)

In [38]: gp
Out[38]: 
      col2
col1      
1        3
2        2

让计数> 2

tf = gp[gp.col2 > 2].reset_index()
df[df.col1 == tf.col1]

Out[41]: 
   col1  col2
0     1     2
1     1     3
2     1     4

【讨论】:

  • 现在我明白了。另一种方法是加入这些数据框,它将删除不匹配的条目,然后我可以删除计数列。
  • jep 可以工作 2. 我通常只使用掩码,然后选择我需要的列
猜你喜欢
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多