在Pandas中进行分组后,过滤行数据

7

I have a table in pandas:

import pandas as pd

df = pd.DataFrame({
    'LeafID':[1,1,2,1,3,3,1,6,3,5,1],
    'pidx':[10,10,300,10,30,40,20,10,30,45,20],
    'pidy':[20,20,400,20,15,20,12,43,54,112,23],
    'count':[10,20,30,40,80,10,20,50,30,10,70],
    'score':[10,10,10,22,22,3,4,5,9,0,1]
})

LeafID  count       pidx     pidy   score
0   1       10           10        20     10
1   1       20           10        20     10
2   2       30          300       400     10
3   1       40           10        20     22
4   3       80           30        15     22
5   3       10           40        20      3
6   1       20           20        12      4
7   6       50           10        43      5
8   3       30           20        54      9
9   5       10           45       112      0
10  1       70           20        23      1

我希望进行groupby操作,然后过滤出出现pidx大于2次的行。
也就是说,筛选出pidx为10和20的行。
我尝试使用df.groupby('pidx').count(),但并没有帮助我。对于这些行,我还需要执行0.4*count+0.6*score的操作。
期望的输出结果是:
LeafID    count       pidx     pidy    final_score
   1       10           10        20
   1       20           10        20
   1       40           10        20
   6       50           10        43
   1       20           20        12
   3       30           20        54
   1       70           20        23

需要删除在pydx中同时包含10和20的所有行吗? - jezrael
@jezrael 看编辑,我更新了所需的输出,我想要所有出现 pidx 大于 2 的行,即 10 出现 4 次,2 出现 3 次。 - Shubham R
Pandas是一个非常强大的工具。使用索引可以使代码更加简洁。请查看我的回答。 - V Shreyas
4个回答

10

这是在对分组数据进行筛选后直接应用过滤器的简单应用。在您提供的数据中,pidx的值为20只出现了两次,因此被过滤掉了。

df.groupby('pidx').filter(lambda x: len(x) > 2)

   LeafID  count  pidx  pidy
0       1     10    10    20
1       1     20    10    20
3       1     40    10    20
7       6     50    10    43

7
你可以使用 value_counts 函数与 boolean indexingisin 函数一起使用:
df = pd.DataFrame({
    'LeafID':[1,1,2,1,3,3,1,6,3,5,1],
    'pidx':[10,10,300,10,30,40,20,10,30,45,20],
    'pidy':[20,20,400,20,15,20,12,43,54,112,23],
    'count':[10,20,30,40,80,10,20,50,30,10,70],
    'score':[10,10,10,22,22,3,4,5,9,0,1]
})
print (df)
    LeafID  count  pidx  pidy  score
0        1     10    10    20     10
1        1     20    10    20     10
2        2     30   300   400     10
3        1     40    10    20     22
4        3     80    30    15     22
5        3     10    40    20      3
6        1     20    20    12      4
7        6     50    10    43      5
8        3     30    30    54      9
9        5     10    45   112      0
10       1     70    20    23      1

s = df.pidx.value_counts()
idx = s[s>2].index
print (df[df.pidx.isin(idx)])
   LeafID  count  pidx  pidy  score
0       1     10    10    20     10
1       1     20    10    20     10
3       1     40    10    20     22
7       6     50    10    43      5

时序:

np.random.seed(123)
N = 1000000


L1 = list('abcdefghijklmnopqrstu')
L2 = list('efghijklmnopqrstuvwxyz')
df = pd.DataFrame({'LeafId':np.random.randint(1000, size=N),
                   'pidx': np.random.randint(10000, size=N),
                   'pidy': np.random.choice(L2, N),
                   'count':np.random.randint(1000, size=N)})
print (df)


print (df.groupby('pidx').filter(lambda x: len(x) > 120))

def jez(df):
    s = df.pidx.value_counts()
    return df[df.pidx.isin(s[s>120].index)]

print (jez(df))

In [55]: %timeit (df.groupby('pidx').filter(lambda x: len(x) > 120))
1 loop, best of 3: 1.17 s per loop

In [56]: %timeit (jez(df))
10 loops, best of 3: 141 ms per loop

In [62]: %timeit (df[df.groupby('pidx').pidx.transform('size') > 120])
10 loops, best of 3: 102 ms per loop

In [63]: %timeit (df[df.groupby('pidx').pidx.transform(len) > 120])
1 loop, best of 3: 685 ms per loop

In [64]: %timeit (df[df.groupby('pidx').pidx.transform('count') > 120])
10 loops, best of 3: 104 ms per loop

对于final_score,您可以使用以下方法:

df['final_score'] = df['count'].mul(.4).add(df.score.mul(.6))

添加了一个分数列,其中对于那些行,我需要执行0.4count+0.6score,并创建一个新的列final_score。 - Shubham R
Jezrael,我们能在一步中完成这个操作吗,还是需要先进行 df.div('count') 然后再加上 df.score? - Shubham R
所以我猜 df[df.groupby('pidx').pidx.transform('count') > 120] 对于较大的数据框来说是最好的。 - Shubham R
是的 - 这是piRSquared的解决方案。 - jezrael
1
@piRSquared - 我测试了你的numpy解决方案,它返回带有[1000000行x 4列]df,而所有其他解决方案都返回[27982行x 4列],所以我认为肯定有什么问题... :( - jezrael
显示剩余4条评论

3

pandas

df[df.groupby('pidx').pidx.transform('count') > 2]


   LeafID  count  pidx  pidy  score
0       1     10    10    20     10
1       1     20    10    20     10
3       1     40    10    20     22
7       6     50    10    43      5

0
首先,你的输出显示你不想进行分组。了解一下groupby的作用。你需要的是:
df2 = df[df['pidx']<=20]
df2.sort_index(by = 'pidx')

这将给出您精确的结果。 阅读有关pandas索引和函数的内容。事实上,去阅读pandas的整个介绍也不需要太多时间。

使用索引,行操作也很简单:

df2['final_score']= 0.4*df2['count'] + 0.6*df2['score']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接