Skip to content

第 6 章 轴与统计

学习目标

  • 理解 axis(轴)的含义,掌握按轴聚合
  • 掌握常用统计函数:summeanmedianmaxminstdvar
  • 掌握 cumsumprodargmax
  • 会用 keepdims 保持维度

6.1 什么是轴(axis)

轴(axis)是数组的维度方向。二维数组有两个轴:axis=0 沿行方向(从上到下,跨行),axis=1 沿列方向(从左到右,跨列)。

用 4 个学生 × 3 门课的成绩表理解。行是学生,列是课程:

python
import numpy as np

scores = np.array([[85, 90, 78],   # 学生 1:语文 数学 英语
                   [92, 88, 95],   # 学生 2
                   [76, 84, 80],   # 学生 3
                   [88, 91, 87]])  # 学生 4
print(scores.shape)

输出:

(4, 3)

scores.mean(axis=0) 沿行方向聚合:对每一列(同一门课)的 4 个学生求平均,结果是「每门课的平均分」,长度 3。

scores.mean(axis=1) 沿列方向聚合:对每一行(同一个学生)的 3 门课求平均,结果是「每个学生的平均分」,长度 4。

python
import numpy as np

print(scores.mean(axis=0))    # 每门课的平均分(列平均)
print(scores.mean(axis=1))    # 每个学生的平均分(行平均)

输出:

[85.25 88.25 85.  ]
[84.33333333 91.66666667 80.         88.66666667]

记忆法:哪个轴=哪个方向,聚合后该维度消失

  • axis=0 聚合后,shape 从 (4, 3) 变成 (3,):行维度(4)消失。
  • axis=1 聚合后,shape 从 (4, 3) 变成 (4,):列维度(3)消失。

不指定 axis 时,聚合作用于所有元素,结果是一个标量:scores.mean() 是全部 12 个分数的平均(86.166...)。

6.2 常用统计函数

一维数组上,统计函数作用于全部元素:

python
import numpy as np

a = np.array([1, 2, 3, 4, 5])
print("总和:", a.sum())
print("平均:", a.mean())
print("标准差:", a.std())
print("方差:", a.var())

输出:

总和: 15
平均: 3.0
标准差: 1.4142135623730951
方差: 2.0

标准差(std)衡量数据偏离平均值的程度,方差是标准差的平方。数据越分散,std 越大。二维数组按轴统计:

python
import numpy as np

scores = np.array([[85, 90, 78],
                   [92, 88, 95],
                   [76, 84, 80],
                   [88, 91, 87]])
print(scores.sum(axis=0))       # 每门课总分
print(scores.max(axis=0))       # 每门课最高分
print(scores.max(axis=1))       # 每个学生最高分
print(np.median(scores, axis=0))  # 每门课中位数
print(np.std(scores, axis=0))     # 每门课标准差

输出:

[341 353 340]
[92 91 95]
[90 95 84 91]
[86.5 89.  83.5]
[5.88960949 2.68095132 6.67083203]

注意 medianstd 等函数既可以写成 np.median(a),也可以写成方法 a.std();sum/mean/max/min 两者都行,median 只有函数形式。

标准差含义示例:英语课(std≈6.67)学生差异最大,数学课(std≈2.68)最平均——std 越大,这组数越分散。

6.3 cumsum 与 prod

cumsum(累计和):前 n 个元素之和组成的数组。

prod(乘积):全部元素相乘。

python
import numpy as np

print(np.cumsum(np.array([1, 2, 3, 4])))
print(np.prod(np.array([1, 2, 3, 4])))

输出:

[ 1  3  6 10]
24

cumsum 适合看「累计进度」,比如月度累计销量:

python
import numpy as np

monthly = np.array([120, 95, 150, 80])     # 每月销量
print(np.cumsum(monthly))                  # 累计销量

输出:

[120 215 365 445]

6.4 argmax 与 argmin

argmax(数组, axis=...) 返回最大值的下标(而不是最大值本身),argmin 同理。

python
import numpy as np

scores = np.array([[85, 90, 78],
                   [92, 88, 95],
                   [76, 84, 80],
                   [88, 91, 87]])
print(scores.argmax(axis=0))    # 每门课最高分是哪个学生(行号)

输出:

[1 3 1]

解读:语文最高分是学生下标 1(92 分),数学是下标 3(91 分),英语是下标 1(95 分)。

6.5 keepdims:聚合后保留维度

keepdims=True 让聚合结果保留原轴的维度(变成长度 1),方便后续与原始数组做形状兼容的运算:

python
import numpy as np

scores = np.array([[85, 90, 78],
                   [92, 88, 95],
                   [76, 84, 80],
                   [88, 91, 87]])
print(scores.mean(axis=0))
print(scores.mean(axis=0, keepdims=True))   # 形状 (1, 3)

输出:

[85.25 88.25 85.  ]
[[85.25 88.25 85.  ]]

keepdims 的结果是 (1, 3),可以直接与 (4, 3) 的数组按广播规则运算(第 7 章),例如求每个分数相对本门课平均分的差值:

python
import numpy as np

scores = np.array([[85, 90, 78],
                   [92, 88, 95],
                   [76, 84, 80],
                   [88, 91, 87]])
course_mean = scores.mean(axis=0, keepdims=True)
print(scores - course_mean)

输出:

[[-0.25  1.75 -7.  ]
 [ 6.75 -0.25 10.  ]
 [-9.25 -4.25 -5.  ]
 [ 2.75  2.75  2.  ]]

动手实践

  1. 创建 3×3 成绩表(自己设计数据),分别计算:全部平均、每列平均、每行平均,并解释三个结果分别代表什么。
  2. std(axis=0) 找出一组学生数据中「哪门课差距最大」。
  3. 计算 4 个学生每人 3 门课的总分与平均分,验证「行平均 × 3 = 行总分」。
  4. argmax(axis=1) 找出每个学生最高分对应的是哪门课(下标 0/1/2)。

常见错误

错误写法现象原因
混淆 axis=0 与 axis=1 的方向统计结果含义反了axis=0 沿行方向聚合(按列统计),axis=1 沿列方向聚合(按行统计)
忘记聚合后维度消失形状对不上axis=0 聚合把行数变没了;需要保留用 keepdims=True
np.median(a) 写成 a.median()AttributeError: 'ndarray' object has no attribute 'median'median 没有方法形式,要用 np.median(a)
期望 std 衡量「平均数的差距」概念混淆std 是离散程度;平均差距概念用 np.abs(a - a.mean()).mean()
不指定 axis 时得到全数组的标量对多维数组要明确 axis,否则聚合所有元素

章末练习

基础

  1. np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 计算:全部总和、axis=0 总和、axis=1 总和。
  2. 计算 np.array([4, 8, 6, 5, 3]) 的平均值与标准差。
  3. cumsum 计算 [10, 20, 15, 5] 的累计和。

提高

  1. 某班 5 名学生 4 门课成绩(自行设计),求:每门课平均分、每个学生总分、全班最高分及它所在位置(用 argmax)。
  2. keepdims=True 计算每列平均,再用原始数组减它,得到「每门课相对平均分的差值」。

挑战

  1. 生成 np.arange(1, 25).reshape(4, 6),不写循环,计算每行的最大值、每列的最大值,以及整个数组的最大值与它的位置(提示:np.unravel_index(np.argmax(a), a.shape))。
  2. np.std 对比 [1, 2, 3, 4, 5][1, 1, 1, 5, 5] 两组数的离散程度,并解释为什么。

章末自测

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. a = np.array([[1, 2], [3, 4]]); a.sum(axis=0) 的结果是?
    • A. [4, 6]
    • B. [3, 7]
    • C. 10
    • D. [1, 2, 3, 4]
  2. a.sum(axis=1) 的结果是?
    • A. [4, 6]
    • B. [3, 7]
    • C. 10
    • D. [1, 2, 3, 4]
  3. 不指定 axis 时,a.sum() 的结果是?
    • A. [4, 6]
    • B. [3, 7]
    • C. 10
    • D. 报错
  4. np.median(a) 的正确调用方式是?
    • A. a.median()
    • B. np.median(a)
    • C. 两者都可以
    • D. median(a)
  5. 标准差衡量的是?
    • A. 数据总和
    • B. 数据偏离平均值的程度
    • C. 数据个数
    • D. 最大值
  6. keepdims=True 的作用是?
    • A. 让聚合结果保留长度为 1 的维度
    • B. 让聚合速度更快
    • C. 只统计非零元素
    • D. 返回视图
  7. np.cumsum(np.array([1, 2, 3])) 的结果是?
    • A. [1, 2, 3]
    • B. [1, 3, 6]
    • C. 6
    • D. [1, 2, 3, 6]
  8. np.argmax(np.array([3, 7, 5])) 的结果是?
    • A. 7
    • B. 1
    • C. 2
    • D. 3
  9. 形状 (4, 3) 的数组做 mean(axis=0) 后形状是?
    • A. (4,)
    • B. (3,)
    • C. (4, 3)
    • D. ()
  10. 全班 3 门课成绩按列求平均,应使用?
    • A. scores.mean(axis=0)
    • B. scores.mean(axis=1)
    • C. scores.mean()
    • D. scores.median(axis=1)