📊 第4章 Pandas 进阶
📄 一句话概括

sum、mean、max、min 四个函数默认都是「一列一列地算」,返回一个 Series。 想横着按行算,要显式写 axis=1。默认的 axis=0 是竖着算。 数值列和文本列混在一张表里,sum 会把文本拼起来——不报错,但结果没用。

📝 本章和前面几章的关系

第 3 章把表读进来、看清楚了,从这一章开始算。先算最朴素的四个量。 还是那张 10 行成绩表。语文合计 827、数学 830、英语 819,都是现算的。

一、按列求和:sum

df.sum() 不给参数,一列一列往下加,返回一个 Series,索引是列名。 语文 827、数学 830、英语 819。总分那一列加起来是 2476,等于三科之和。 姓名和班级是字符串列,sum 会把它们拼成一长串。不是报错,是安静地拼。

所以 sum 之前先挑列:df[ ['语文', '数学', '英语'] ].sum()。 看到「求和结果是一串文字」,就是这个原因,回头挑列就好。

二、按行求和:axis=1

df[ ['语文','数学','英语']].sum(axis=1) 一行算一个数出来,得到 265、277、223。

姓名 语文 数学 英语 三科合计
张伟 88 92 85 265
王芳 92 95 90 277
李娜 75 68 80 223

这三行的合计和总分列一模一样——等于给总分做了一次免费验算。 对不上就说明总分列有问题:要么录错,要么有人改过其中一科没改总分。

三、axis 到底指哪个方向

写法 方向 结果
sum() 竖着加(沿行往下) 每列一个数
sum(axis=1) 横着加(沿列往右) 每行一个数

记法:axis 是「要被压掉的那根轴」。 axis=0 压掉行,剩下的是一列一个值;axis=1 压掉列,剩下的是一行一个值。 这个记法比「0 是行 1 是列」靠谱,因为后者会让人以为 axis 指的是保留哪根轴。

四、均值:mean

语文 82.70、数学 83.00、英语 81.90。三科相当接近。 mean() 会自动跳过缺失值:分母是「有几个数」,不是「有几行」。 这两者在没有缺失时一样,有缺失时差得远。报均值必须说清分母是哪种。

要按总行数平摊,自己写 df['语文'].sum() / len(df),别用 mean。

五、最大值与最小值

三科最高都是 95,最低分别是语文 68、数学 65、英语 60。 只有数看不出是谁。idxmax() 给「最大值在哪一行」,配着用才完整。 数学最高那一行是王芳:语文 92、数学 95、英语 90、总分 277。

idxmax 给的是行标签。第 3 章说过标签比位置可靠,这里正是它的用处。 有并列时 idxmax 只给第一个,要全找出来得用 df[df['数学'] == df['数学'].max()]。

六、动手 Demo:求和、均值、最大最小

先按列算四个量,再按行求和验证总分,最后用 idxmax 找出最高分是谁。 注意 sum 在字符串列上的表现——这是本篇最该记住的一脚。

import pandas as pd

DF = pd.DataFrame({
    "姓名": ["张伟", "王芳", "李娜", "刘洋", "陈静",
             "杨帆", "赵敏", "黄磊", "周涛", "吴霞"],
    "班级": ["一班"] * 5 + ["二班"] * 5,
    "语文": [88, 92, 75, 85, 90, 68, 95, 72, 83, 79],
    "数学": [92, 95, 68, 88, 73, 82, 91, 65, 86, 90],
    "英语": [85, 90, 80, 79, 95, 71, 88, 60, 84, 87],
})
DF["总分"] = DF["语文"] + DF["数学"] + DF["英语"]

print("三科合计 %s" % DF[ ["语文", "数学", "英语"]].sum().tolist())
print("三科均值 %s" % DF[ ["语文", "数学", "英语"]].mean().round(2).tolist())
print("总分合计 %d" % DF["总分"].sum())

H = DF[ ["语文", "数学", "英语"]].sum(axis=1)
print("按行加和总分一致:%s" % bool((H == DF["总分"]).all()))

print("数学最高 %d,是 %s" % (DF["数学"].max(),
                               DF.loc[DF["数学"].idxmax(), "姓名"]))

实跑输出:

--------------------------------------------------------------------
求和、均值、最大最小
--------------------------------------------------------------------

  ① 按列求和:sum
  --------------------------------------------------------------------
  df.sum() 不给参数,默认一列一列地加,返回一个 Series。
  语文合计 827,数学合计 830,英语合计 819。
  姓名和班级是字符串列,sum 会把它们拼起来——不是报错,是连成一长串。
  ! 数值列和文本列混在一张表里,sum 之前先挑列。这是最容易踩的一脚。

  ② 按行求和:axis=1
  --------------------------------------------------------------------

| 行 | 姓名 | 语文 | 数学 | 英语 | 三科合计 |
|---|---:|---:|---:|---:|---:|
| 0 | 张伟 | 88 | 92 | 85 | 265 |
| 1 | 王芳 | 92 | 95 | 90 | 277 |
| 2 | 李娜 | 75 | 68 | 80 | 223 |

  axis=1 是「横着加」,一行加一个数出来。默认 axis=0 是「竖着加」。
  三科合计和总分列一模一样——这等于给总分做了一次验算。
  ! axis 这个参数记法:axis=0 沿着行往下走(结果是每列一个数),axis=1 沿着列往右走。

  ③ 均值:mean
  --------------------------------------------------------------------
  语文 82.70,数学 83.00,英语 81.90。
  mean 会自动跳过缺失值,分母是「有几个数」而不是「有几行」。
  ! 有缺失时 mean 和 sum/len 不等——想按总行数平摊,得自己写 sum()/len(df)。

  ④ 最大值与最小值:max 和 min
  --------------------------------------------------------------------
  语文最高 95,数学最高 95,英语最高 95。
  语文最低 68,数学最低 65,英语最低 60。
  只给最大最小看不出是谁,要名字得用 idxmax 拿到行标签再回头查。
  数学最高那行:姓名=王芳、班级=一班、语文=92、数学=95、英语=90、总分=277。
  ! max 给的是值,idxmax 给的是「哪个位置」,两个配着用才完整。

  ⑤ 四个函数一张表
  --------------------------------------------------------------------

| 函数 | 给什么 | 默认方向 |
|---|---|---|
| sum() | 合计 | 按列(axis=0) |
| mean() | 平均值 | 按列 |
| max() | 最大值 | 按列 |
| min() | 最小值 | 按列 |
| idxmax() | 最大值的位置 | 按列 |

  五个函数都认 axis 参数,想按行算就写 axis=1。

(H == DF['总分']).all() 给 True,说明每一行都对得上——这比肉眼看三行可靠。 sum 遇上字符串列不报错。这是 Pandas 最「温柔」也最坑人的一处设计。

30 秒实验

  1. 把 sum() 的列挑掉,直接 DF.sum(),看姓名那一项变成什么。
  2. 把 axis=1 改成 axis=0,看返回的东西从 10 个数变成几个数。
  3. 想一想:如果有两个人数学都是最高分,idxmax 会给几个名字?

常见误区

  1. 直接 DF.sum():文本列被拼成一大串,还以为数据坏了。
  2. 以为 axis=1 是「按列」:方向记反,结果形状不对。
  3. 用 mean 当「除以总行数」:有缺失时算出来的数偏大。
  4. 只报 max 不报是谁:「最高 95 分」这句话对读者毫无用处。
自测三问(点开对答案) 1. sum() 和 sum(axis=1) 分别返回什么? —— 前者每列一个和(索引是列名),后者每行一个和(索引是行标签)。 2. 为什么 sum 会把姓名拼起来? —— 字符串的加法在 Python 里就是拼接,Pandas 沿用了这个语义,所以不报错。 3. idxmax 和 max 各给什么? —— max 给最大的那个值,idxmax 给这个值所在的行标签。两个配着用才知道是谁。

四个基本量讲完。下一篇补两个「平均数」:中位数与众数,专治极端值。

相关笔记