Python 如何在pandas中创建求和行和求和列?

Python 如何在pandas中创建求和行和求和列?,python,pandas,Python,Pandas,我正在学习可汗学院的统计学课程,这是我大学时代的一点复习,也是让我了解熊猫和其他科学巨蟒的一种方式 我有一张来自汗学院的桌子,看起来像这样: | Undergraduate | Graduate | Total -------------+---------------+----------+------ Straight A's | 240 | 60 | 300 -------------+---------------+-----

我正在学习可汗学院的统计学课程,这是我大学时代的一点复习,也是让我了解熊猫和其他科学巨蟒的一种方式

我有一张来自汗学院的桌子,看起来像这样:

             | Undergraduate | Graduate | Total
-------------+---------------+----------+------
Straight A's |           240 |       60 |   300
-------------+---------------+----------+------
Not          |         3,760 |      440 | 4,200
-------------+---------------+----------+------
Total        |         4,000 |      500 | 4,500
我想用熊猫重新制作这张桌子。当然,我可以使用以下方法创建数据帧

"Graduate": {...},
"Undergraduate": {...},
"Total": {...},
但这似乎是一种幼稚的方法,既会很快失败,又不会真正扩展

表中的非总计部分如下所示:

df = pd.DataFrame(
    {
        "Undergraduate": {"Straight A's": 240, "Not": 3_760},
        "Graduate": {"Straight A's": 60, "Not": 440},
    }
)
df
我一直在寻找并发现了一些有前途的东西,比如:

df['Total'] = df.sum(axis=1)
但是我没有发现任何非常优雅的东西

我确实找到了
交叉表
函数,它看起来应该做我想做的事情,但为了做到这一点,我必须为所有这些值创建一个由1/0组成的数据帧,这看起来很愚蠢,因为我已经得到了一个聚合

我发现一些方法似乎可以手动构建新的总计行,但似乎应该有更好的方法,例如:

totals(df, rows=True, columns=True)
或者别的什么

熊猫是否存在这种情况,还是我必须拼凑出自己的方法?

和 这个答案的要点是提供一个在线而非就地解决方案

我使用
append
垂直堆叠
Series
DataFrame
。它还创建了一个
副本
,以便我可以继续链接

我使用
assign
添加列。但是,我正在处理的
DataFrame
位于中间的虚空中。因此我在
assign
参数中使用
lambda
,它告诉
Pandas
将其应用于调用的
DataFrame



有趣的选择 使用
drop
errors='ignore'
删除可能预先存在的
Total
行和列

还有,还在排队

def tc(d):
  return d.assign(Total=d.drop('Total', errors='ignore', axis=1).sum(1))

df.pipe(tc).T.pipe(tc).T

              Graduate  Undergraduate  Total
Not                440           3760   4200
Straight A's        60            240    300
Total              500           4000   4500

或者分两步,按照您的建议使用
.sum()
函数(也可能可读性更强):

输出:

              Graduate  Undergraduate  Total
Not                440           3760   4200
Straight A's        60            240    300
Total              500           4000   4500

从原始数据使用
交叉表
,如果仅仅基于您的输入,您只需要在
交叉表

s=df.reset_index().melt('index')
pd.crosstab(index=s['index'],columns=s.variable,values=s.value,aggfunc='sum',margins=True)
Out[33]: 
variable      Graduate  Undergraduate   All
index                                      
Not                440           3760  4200
Straight A's        60            240   300
All                500           4000  4500

玩具数据

df=pd.DataFrame({'c1':[1,2,2,3,4],'c2':[2,2,3,3,3],'c3':[1,2,3,4,5]}) 
# before `agg`, I think your input is the result after `groupby` 
df
Out[37]: 
   c1  c2  c3
0   1   2   1
1   2   2   2
2   2   3   3
3   3   3   4
4   4   3   5


pd.crosstab(df.c1,df.c2,df.c3,aggfunc='sum',margins
=True)
Out[38]: 
c2     2     3  All
c1                 
1    1.0   NaN    1
2    2.0   3.0    5
3    NaN   4.0    4
4    NaN   5.0    5
All  3.0  12.0   15
原始数据为:

>>> df = pd.DataFrame(dict(Undergraduate=[240, 3760], Graduate=[60, 440]), index=["Straight A's", "Not"])
>>> df
Out: 
              Graduate  Undergraduate
Straight A's        60            240
Not                440           3760
您只能使用
df.T
来实现重新创建此表:

>>> df_new = df.T
>>> df_new
Out: 
               Straight A's   Not
Graduate                 60   440
Undergraduate           240  3760
按行和列计算
总数后:

>>> df_new.loc['Total',:]= df_new.sum(axis=0)
>>> df_new.loc[:,'Total'] = df_new.sum(axis=1)
>>> df_new
Out: 
               Straight A's     Not   Total
Graduate               60.0   440.0   500.0
Undergraduate         240.0  3760.0  4000.0
Total                 300.0  4200.0  4500.0

呵呵。。。这给了我一些奇怪的输出,虽然-3760+440不是8400,但这就是它所显示的??这很奇怪,我得到了4200,这是它应该得到的吗?也许是打字错误?@WayneWerner这是因为这是一个就地操作。看来你已经运行了两次了,我一定是不小心在笔记本上按了ctrl+enter。这一次我做了一份复印件来操作:)
>>> df_new = df.T
>>> df_new
Out: 
               Straight A's   Not
Graduate                 60   440
Undergraduate           240  3760
>>> df_new.loc['Total',:]= df_new.sum(axis=0)
>>> df_new.loc[:,'Total'] = df_new.sum(axis=1)
>>> df_new
Out: 
               Straight A's     Not   Total
Graduate               60.0   440.0   500.0
Undergraduate         240.0  3760.0  4000.0
Total                 300.0  4200.0  4500.0