【问题标题】:Most common value from multiple colums in PandasPandas 中多列中最常见的值
【发布时间】:2016-11-16 09:10:59
【问题描述】:

我在不规则数量的列中有一系列数据,我需要使用 pandas 从跨多列的拆分部分中确定最常见的值。我的意思的一个例子是,如果我知道我的同事每天午餐吃哪种奶酪:

Idx Name   Cheese1   Cheese2   Cheese3
0   Evan   Gouda     NaN       NaN
1   John   Cheddar   Havarti   Blue
2   Evan   Cheddar   Gouda     NaN
3   John   Havarti   Swiss     NaN

我正在寻找某种可以提供结果数据透视表的功能:

Name    Cheese    Pct
Evan    Gouda     .66
John    Havarti   .4

我也不知道每次运行脚本时需要包含多少列,只知道它们的格式都是“Cheese”+index。如果第二天约翰带着四块奶酪出现,我需要添加第四列,并且分析脚本需要能够处理它。

【问题讨论】:

    标签: python pandas statistics


    【解决方案1】:
    import io
    import pandas as pd
    
    data = io.StringIO("""\
    Idx Name   Cheese1   Cheese2   Cheese3
    0   Evan   Gouda     NaN       NaN
    1   John   Cheddar   Havarti   Blue
    2   Evan   Cheddar   Gouda     NaN
    3   John   Havarti   Swiss     NaN
    4   Rick   NaN       NaN       NaN
    """)
    df = pd.read_csv(data, delim_whitespace=True)
    
    def top_cheese(g):
        cheese_cols = [col for col in g.columns if col.startswith('Cheese')]
        try:
            out = (g[cheese_cols].stack().value_counts(normalize=True)
                                 .reset_index().iloc[0])
            out.index = ['Cheese', 'Pct']
            return out
        except IndexError:
            return pd.Series({'Cheese': 'None', 'Pct': 0})
    
    
    output = df.groupby('Name').apply(top_cheese)
    print(output)
    

    输出:

           Cheese       Pct
    Name                   
    Evan    Gouda  0.666667
    John  Havarti  0.400000
    Rick     None  0.000000
    

    【讨论】:

    • 您错过了将函数命名为big_cheese的机会
    • 这行得通,但是当所有人都吃相同的最常见的奶酪时,它就失效了。相反,它将名称作为列标题而不是索引。有什么办法可以解决吗?
    • 我通过使用 try-except 语句来获取索引或列名来修复它,但它很笨拙,如果有人有的话,我想要一个更好的解决方案。
    • 这行得通。我实际上并不关心droplevel,但无论如何都感谢你把它放在那里!我还将函数更改为 try/except 返回语句,因为我的一些同事根本不带奶酪,所以他们的所有行都是空的。我包括:except: return pd.Series(data = [0], index = ['None']).reset_index(),效果很好。
    • 最后一次更新。将.iloc[[0]] 更改为.iloc[0] 会返回Series 并避免不得不降低一个级别。在top_cheese() 内移动索引。添加了您的 try/except 逻辑。瑞克怎么了?没有奶酪?哦,人类!
    【解决方案2】:

    最近,我一直在使用R,我会像这样解决这个问题:

    library(data.table)
    library(dplyr)
    library(tidyr)
    
    x <- fread('
    Idx Name   Cheese1   Cheese2   Cheese3
    0   Evan   Gouda     NaN       NaN
    1   John   Cheddar   Havarti   Blue
    2   Evan   Cheddar   Gouda     NaN
    3   John   Havarti   Swiss     NaN', na = 'NaN')
    
    gather(x, , Cheese, matches('Cheese'), na.rm = T) %>%
      group_by(Name, Cheese) %>%
      summarise(n = n()) %>%
      group_by(Name) %>%
      mutate(p = n/sum(n)) %>%
      filter(p == max(p)) %>%
      select(-n)
    

    哪些输出:

       Name  Cheese         p
      (chr)   (chr)     (dbl)
    1  Evan   Gouda 0.6666667
    2  John Havarti 0.4000000
    

    我很想知道在 Pandas 中类似的东西会是什么样子。这是我想出的:

    import io
    import pandas as pd
    
    x = pd.read_csv(io.StringIO('''
    Idx Name   Cheese1   Cheese2   Cheese3
    0   Evan   Gouda     NaN       NaN
    1   John   Cheddar   Havarti   Blue
    2   Evan   Cheddar   Gouda     NaN
    3   John   Havarti   Swiss     NaN'''), delim_whitespace=True)
    
    tidy = pd.melt(x, ['Idx', 'Name'], value_name='Cheese').dropna()
    tidy = tidy.groupby(['Name', 'Cheese']).size().reset_index(name='n')
    tidy['p'] = tidy.groupby('Name')['n'].transform(lambda n: n/sum(n))
    tidy[tidy['p'] == tidy.groupby('Name')['p'].transform('max')].drop('n', 1)
    

    哪些输出:

       Name   Cheese         p
    1  Evan    Gouda  0.666667
    4  John  Havarti  0.400000
    

    肯定不如 R 干净,但也许更熟悉 Pandas 的人可以权衡一下如何改进它。

    【讨论】:

      猜你喜欢
      • 2017-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      相关资源
      最近更新 更多