【问题标题】:pandas pivot_table's margins is only aggregating verticallypandas pivot_table 的边距仅垂直聚合
【发布时间】:2020-05-05 18:36:56
【问题描述】:

考虑一个数据框:

df = pd.DataFrame(
    {'last_year': [1, 2, 3], 'next_year': [4, 5, 6]}, 
    index=['foo', 'bar', 'star']
)
      last_year  next_year
foo           1          4
bar           2          5
star          3          6

我正在寻找一种简单的方法来显示此表周围的总计,包括列和行。

我的想法是通过.pivot_table()

pd.pivot_table(
    df,
    index=df.index,
    margins=True,
    aggfunc=sum
)

但是,这只适用于第一个轴(垂直):

      last_year  next_year
bar           2          5
foo           1          4
star          3          6
All           6         15

我错过了什么?像this documentation's example 一样,为什么没有按行计算总计?另外,为什么会弄乱我的索引顺序?

我对@9​​87654327@ 之类的解决方案不感兴趣;我想要一种不影响我原始数据框的动态方法。数据透视表似乎是最合乎逻辑的方法(据我所知),但也许还有更好的方法!

【问题讨论】:

    标签: python pandas pivot-table


    【解决方案1】:

    我的猜测是pivot_table 中的每一列都是它自己的组,因此您看不到水平聚合(聚合单个元素是毫无意义的)。为了证明差异,请考虑stack()

    (df.stack().reset_index(name='value')
       .pivot_table(index='level_0', columns='level_1', values='value', margins=True,
                   aggfunc='sum')
    ) 
    

    输出:

    level_1  last_year  next_year  All
    level_0                           
    bar              2          5    7
    foo              1          4    5
    star             3          6    9
    All              6         15   21
    

    也就是说,这很可能是一个错误。

    【讨论】:

    • 嗯,实际上是因为传递 index= 而不是 columns= 作为 grouper 对象,我希望这些组被聚合,这意味着水平总计!
    • 好的,我现在得到你的答案,经过@Andy L. 的彻底解释,我发现我需要“取消透视”last_yearnext_year,然后才能聚合它们。看着df.stack().reset_index() 不旋转就清楚了。
    【解决方案2】:

    当您没有在pivot_table 中指定valuescolumns 参数时。它将使用values 的所有列。由于您仅指定index 参数,其余列last_yearnext_year 用作聚合值。即,Pandas 认为您想将 sum 函数应用于列的值 last_year, next_year

    由于df 的所有列都用于values 参数,pivot_table 不会将任何内容旋转到列 (axis=1)。因此,它没有理由对axis=1 执行margins

    试试这个样本

    Out[132]:
          last_year  next_year
    foo           1          4
    bar           2          5
    star          3          6
    bar          33         66
    
    pd.pivot_table(df, index=df.index, margins=True, aggfunc=sum)
    
    Out[134]:
          last_year  next_year
    bar          35         71
    foo           1          4
    star          3          6
    All          39         81
    

    所以,pivot_tableindex 的每组 bar3571 上对两列 last_yearnext_year 应用 sum,最后它在 axis= 上计算 margins 0。没有旋转到轴 = 1,因此它不会在轴 = 1 上执行 margins

    要查看 pivot_table 使用 values 参数的所有列,您可以尝试使用此命令查看 keyerror

    pd.pivot_table(df, index=df.index, margins=True, aggfunc={'last_year': sum})
    
    .....
        220                     grand_margin[k] = getattr(v, aggfunc)()
        221                 elif isinstance(aggfunc, dict):
    --> 222                     if isinstance(aggfunc[k], compat.string_types):
        223                         grand_margin[k] = getattr(v, aggfunc[k])()
        224                     else:
    
    KeyError: 'next_year'
    

    当为 aggfunc 使用 dict 时,pivot_tablevalues 参数中的每一列传递给 dict 以获取相应的 aggfunc。如您在上面看到的,我没有在字典中指定列next_year。因此,当pivot_table在dict中查找它的aggfunc时,它会返回keyerror。

    【讨论】:

    • 感谢您的详尽解释,这帮助我了解了真正发生的事情。
    【解决方案3】:

    我不知道这是否会有所帮助,但我切换了列和行以便进行汇总。对于改进的代码,您能否更深入地解释动态方法?谢谢,我希望这会有所帮助!

    df43 = pd.DataFrame(
    {'last_year': [1, 2, 3], 'next_year': [4, 5, 6]}, 
    index=['foo', 'bar', 'star'])
    df43 = df43.T #.T is transpose
    df43['total'] = df43.sum(axis=1)
    df43
    

    【讨论】:

    • 我明确声明我不是在寻找df.sum(axis=1) 的答案。为什么.pivot_table() 的行为不像文档中那样?
    【解决方案4】:
    df = pd.DataFrame(
        {'last_year': [1, 2, 3], 'next_year': [4, 5, 6]}, 
        index=['foo', 'bar', 'star']
    )
    
    df.append(df.sum().rename('Total')).assign(Total=lambda d: d.sum(1))
    

    输出:

         last_year   next_year   Total
    foo      1           4         5
    bar      2           5         7
    star     3           6         9
    Total    6          15        21
    

    这不会影响原始数据框!

    【讨论】:

    • 嘿,谢谢,但我真的很想深入了解.pivot_table(),为什么它的行为与文档中的不同?
    • 也许有更好的方法
    【解决方案5】:

    要查看行总数,您需要为 columns= 指定至少一个参数

    所以:

    pd.pivot_table( df, 索引=df.index, 边距=真, 列='last_year' 聚合函数=总和 )

    ...还会为您提供行总计以及您已有的现有列总计。并不是说在您的具体示例中有意义。但基本上,如果您至少旋转一列,pandas pivot 只会为您提供行总数。

    您链接到的文档示例有效(具有行总数),因为它指定了 columns= 的值。

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 2021-08-24
    • 2021-04-03
    • 2022-09-24
    • 2021-03-03
    • 2014-01-23
    • 2011-02-14
    相关资源
    最近更新 更多