【问题标题】:Add index of value_counts() to new column for each group in groupby将 value_counts() 的索引添加到 groupby 中每个组的新列
【发布时间】:2020-09-01 07:35:09
【问题描述】:

这个问题已经有了一些变化,但我找不到我正在寻找的确切内容。

我有一个包含他们购买的产品的客户数据框:

   customer product
0      John    Milk
1      John    Milk
2      John  Shoes 
3      John  Shoes 
4      John  Shoes 
5      John   Bread
6      Mary    Milk
7      Mary    Milk
8      Mary    Milk
9      Mary    Milk
10     Mary    Milk
11     Mary    Milk
12     Mary  Shoes 
13     Mary  Shoes 
14      Joe   Bread
15      Joe   Bread
16      Joe   Bread
17      Joe   Bread
18      Joe    Milk
19      Joe    Milk
20      Joe    Milk
21      Joe   Fruit
22      Joe   Fruit
23      Joe  Shoes 
24      Joe  Shoes 
25      Joe  Shoes 
26      Joe    Beer
27      Joe    Beer
28      Joe    Beer
29      Joe    Beer

注意:在完整的数据框中,客户拥有数百种产品,因此不能只是列中的简单连接/产品集。

我想为每个客户获取前 5 种产品 (value_counts()),并将产品名称放在单独的列中。不是产品的计数,只是产品名称(价值 couts 的索引),以及价值计数的正确顺序。

我的目标是拥有这样的数据框:

  customer                        Top 5
0     John             Shoes Milk Bread
1     Mary                   Milk Shoes
2      Joe  Bread Beer Milk Shoes Fruit

我认为我在这条线上走对了,我可以看到每个客户的 Top 5 产品:

newdf.groupby('customer')['product'].value_counts()

customer  product
Joe       Beer       4
          Bread      4
          Milk       3
          Shoes      3
          Fruit      2
John      Shoes      3
          Milk       2
          Bread      1
Mary      Milk       6
          Shoes      2

我只是无法以我喜欢的格式从此数据框中提取信息。我曾尝试重置索引和切片等,但我似乎无法正确处理。

【问题讨论】:

  • 为什么不直接遍历组呢? groupby 客户和产品,对其进行排序,然后遍历前五个组

标签: python pandas


【解决方案1】:

在 lambda 函数中使用 Series.value_counts 将索引的前 5 个值与 GroupBy.agg 连接起来:

f = lambda x: ' '.join(x.value_counts().index[:5])
df = (newdf.groupby('customer')['product'].agg(f)
           .reset_index(name='Top 5'))
print (df)  
 customer                         Top 5
0      Joe  Bread Beer Shoes Milk Fruit
1     John             Shoes Milk Bread
2     Mary                   Milk Shoes

如果客户的订购很重要:

f = lambda x: ' '.join(x.value_counts().index[:5])
df = (newdf.groupby('customer', sort=False)['product'].agg(f)
           .reset_index(name='Top 5'))
print (df)  
  customer                        Top 5
0     John             Shoes Milk Bread
1     Mary                   Milk Shoes
2      Joe  Bread Beer Shoes Milk Fruit

【讨论】:

  • 感谢您的快速回复。但我只需要前5名。我尝试使用value_counts().head(5),但它不起作用。我知道在我的样本中没有很多产品,但假装有 100 种产品。在您的value_counts 之后,我还尝试了nlargest(5)
  • @SCool - 我尝试简化答案,现在是 top5
【解决方案2】:
from collections import Counter


def fn(s):
    return ", ".join(k for k, v in Counter(s).most_common(5))

df.groupby("customer")["product"].apply(fn)
customer
Joe     Bread, Beer, Milk, Shoes, Fruit
John                 Shoes, Milk, Bread
Mary                        Milk, Shoes
Name: product, dtype: object

【讨论】:

    【解决方案3】:

    试试这个:

    fn = lambda _: _.value_counts().index.to_list()
    df.groupby('customer')['product'].apply(fn).reset_index()
    

    如果你想将Top 5 作为一个字符串而不是一个集合:

    outdf['Top 5'] = outdf['product'].str.join(', ')
    

    【讨论】:

    • 这不是按值计数的顺序。例如,您可以看到,John 排名最高的产品是鞋奶和面包。你的方法是面包鞋牛奶。
    • 明白了,已修改。
    【解决方案4】:

    将函数链接在一起

    s=df.groupby(['customer','product']).size().sort_values(ascending=Fasle).\
         groupby(level=0).head(5).reset_index().\
         groupby('customer').product.agg(','.join)
    customer
    Joe     Bread,Beer,Shoes,Milk,Fruit
    John               Shoes,Milk,Bread
    Mary                     Milk,Shoes
    Name: product, dtype: object
    

    【讨论】:

      猜你喜欢
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-08
      • 2021-04-21
      相关资源
      最近更新 更多