高级熊猫链:groupby之后的链索引.droplevel

时间:2019-02-12 18:45:46

标签: python pandas

我正在尝试按列1分组查找列2中的top2值。

以下是数据框:

# groupby id and take only top 2 values.
df = pd.DataFrame({'id':[1,1,1,1,1,1,1,1,1,2,2,2,2,2], 
                    'value':[20,20,20,30,30,30,30,40, 40,10, 10, 40,40,40]})

我已经完成了不使用链接分组的操作:

x = df.groupby('id')['value'].value_counts().groupby(level=0).nlargest(2).to_frame()
x.columns = ['count']
x.index = x.index.droplevel(0)
x = x.reset_index()
x

结果:

   id  value  count
0   1     30      4
1   1     20      3
2   2     40      3
3   2     10      2

我们可以做到单链操作吗?

到目前为止,我已经做到了:

(df.groupby('id')['value']
 .value_counts()
 .groupby(level=0)
 .nlargest(2)
 .to_frame()
.rename({'value':'count'}))

现在,我停留在如何降低索引级别。 如何在一个链中完成所有这些操作?

4 个答案:

答案 0 :(得分:1)

请尝试以下操作:

(df.groupby('id')['value']
.value_counts()
 .groupby(level=0)
 .nlargest(2)
 .to_frame()).rename(columns={'value':'count'}).reset_index([1,2]).reset_index(drop=True)

答案 1 :(得分:1)

您可以使用applyhead而不使用第二个groupby

df.groupby('id')['value']\
  .apply(lambda x: x.value_counts().head(2))\
  .reset_index(name='count')\
  .rename(columns={'level_1':'value'})

输出:

   id  value  count
0   1     30      4
1   1     20      3
2   2     40      3
3   2     10      2

时间:

#This method
  

每个循环7 ms±116 µs(平均±标准偏差,共运行7次,每个循环100个循环)

#Groupby and groupby(level=0) with nlargest
  

每个循环12.9 ms±136 µs(平均±标准偏差,共运行7次,每个循环100个循环)

答案 2 :(得分:1)

另一个解决方案:

df.groupby('id')['value'].value_counts().rename('count')\
    .groupby(level=0).nlargest(2).reset_index(level=[1, 2])\
    .reset_index(drop=True)

答案 3 :(得分:0)

使用@Scott Boston的解决方案,我做了一些测试,并且 试图避免完全适用,但仍然适用于表现良好 与使用numpy一样:

import numpy as np
import pandas as pd
from collections import Counter

np.random.seed(100)
df = pd.DataFrame({'id':np.random.randint(0,5,10000000), 
                    'value':np.random.randint(0,5,10000000)})

# df = pd.DataFrame({'id':[1,1,1,1,1,1,1,1,1,2,2,2,2,2], 
#                     'value':[20,20,20,30,30,30,30,40, 40,10, 10, 40,40,40]})


print(df.shape)
df.head()

使用申请

%time
df.groupby('id')['value']\
  .apply(lambda x: x.value_counts().head(2))\
  .reset_index(name='count')\
  .rename(columns={'level_1':'value'})

# CPU times: user 3 µs, sys: 0 ns, total: 3 µs
# Wall time: 6.2 µs

不使用al处的应用

%time
grouped = df.groupby('id')['value']

res = np.zeros([2,3],dtype=int)
for name, group in grouped:
  data = np.array(Counter(group.values).most_common(2))


  ids = np.ones([2,1],dtype=int) * name
  data = np.append(ids,data,axis=1)
  res = np.append(res,data,axis=0)

pd.DataFrame(res[2:], columns=['id','value','count'])
# CPU times: user 3 µs, sys: 0 ns, total: 3 µs
# Wall time: 5.96 µs