第 1 章 认识 NumPy
学习目标
- 知道 NumPy 是什么、解决什么问题
- 完成 NumPy 的安装并验证版本
- 会用
import numpy as np导入并创建第一个数组 - 理解
ndarray的三个基本属性:维数、形状、数据类型 - 理解「向量化」:数组运算作用于每个元素,不需要写循环
1.1 NumPy 是什么
NumPy(Numerical Python)是 Python 生态中最基础的科学计算库,核心是 ndarray(n 维数组)对象——一个存储同类型元素、支持整体运算的多维容器。
它解决一个具体问题:Python 列表做数值计算太慢、太啰嗦。比如把 100 万个数字每个加 1,用列表要写循环:
# 列表写法:必须逐个元素处理
nums = list(range(1_000_000))
result = [x + 1 for x in nums]用 NumPy 数组,一次运算作用于整个数组:
import numpy as np
nums = np.arange(1_000_000)
result = nums + 1nums + 1 内部用编译好的 C 代码批量执行,速度比列表循环快几十倍,代码也更短。这种「对整块数据做运算,而不是逐个元素循环」的方式,叫向量化(vectorization)。
本书所有示例基于 NumPy 2.x(写作时最新为 2.5.1)。代码统一在交互环境(REPL)或脚本文件中运行,约定运行方式用 uv run python(见 1.2)。
1.2 安装 NumPy
1.2.1 用 uv 安装(推荐)
本书配套仓库使用 uv 管理 Python 环境。在项目根目录:
$ uv sync完成后验证:
$ uv run python -c "import numpy; print(numpy.__version__)"
2.5.11.2.2 用 pip 安装
如果你已有自己的 Python 环境,直接:
$ pip install numpy
$ python3 -c "import numpy; print(numpy.__version__)"输出 2.x.x 即安装成功。后续所有示例,把 uv run python 换成你自己的 python3 即可。
1.3 导入 NumPy 与创建第一个数组
导入是用 import 语句把库加载进当前程序。NumPy 社区约定统一简写为 np:
import numpy as np数组用 np.array 从列表创建。np.array(列表) 把列表转换成一个 ndarray:
import numpy as np
scores = np.array([85, 92, 78, 90, 88])
print(scores)输出:
[85 92 78 90 88]注意输出与列表的区别:数组打印时元素之间没有逗号,[85 92 78 90 88]。
数组可以和数直接做算术,结果仍是数组:
print(scores + 10) # 每个分数加 10
print(scores * 2) # 每个分数乘 2输出:
[95 102 88 100 98]
[170 184 156 180 176]+、* 逐元素作用于整个数组,这就是 1.1 说的向量化。对比列表:列表的 + 是拼接,* 是重复——语义完全不同,这是新手最容易混淆的地方。
1.4 数组的三个基本属性
每个 ndarray 都有三个必知属性:ndim(维数)、shape(形状)、dtype(数据类型)。
维数(ndim)是数组有几层方括号,一维是向量,二维是矩阵。
形状(shape)是一个元组,每个元素是该维度上的长度。
数据类型(dtype)是数组里元素的类型。ndarray 要求所有元素类型一致。
import numpy as np
a = np.array([1, 2, 3]) # 一维
b = np.array([[1, 2], [3, 4]]) # 二维
print("a:", a.ndim, a.shape, a.dtype)
print("b:", b.ndim, b.shape, b.dtype)输出:
a: 1 (3,) int64
b: 2 (2, 2) int64逐项解读:
a.ndim是1、b.ndim是2:分别是一维、二维。a.shape是(3,):长度为 3 的一维数组(注意只有一个元素的元组要写逗号)。b.shape是(2, 2):2 行 2 列。dtype是int64:64 位整数。元素里只要有一个小数,整个数组就是浮点型:
import numpy as np
c = np.array([1.5, 2.5])
print(c.dtype)输出:
float64也可以在创建时用 dtype 参数指定类型:
import numpy as np
d = np.array([1, 2, 3], dtype=np.float64)
print(d)
print(d.dtype)输出:
[1. 2. 3.]
float64注意打印时浮点数组显示为 1. 2. 3.——每个数带一个小数点,这是浮点数的标准显示格式。
1.5 二维数组的打印格式
二维数组打印成矩阵形状,自动换行对齐:
import numpy as np
grades = np.array([[85, 90], [78, 88], [92, 95]])
print(grades)
print("形状:", grades.shape)输出:
[[85 90]
[78 88]
[92 95]]
形状: (3, 2)形状 (3, 2) 读作「3 行 2 列」:3 个学生,每人 2 门成绩。这个「先学一个量纲,再学怎么操作它」的顺序,贯穿全书。
1.6 数组的简单统计
ndarray 自带常用的统计方法,无需循环:
import numpy as np
scores = np.array([85, 92, 78, 90, 88])
print("总和:", scores.sum())
print("平均:", scores.mean())
print("最大:", scores.max())
print("最小:", scores.min())
print("个数:", scores.size)输出:
总和: 433
平均: 86.6
最大: 92
最小: 78
个数: 5sum 是求和方法,mean 求平均,max/min 求最大/最小,size 是元素总数。这些方法在二维数组上默认作用于全部元素,「按轴统计」在第 6 章展开。
1.7 读懂第一条报错
NumPy 报错和 Python 报错格式一样,是 traceback。常见的第一条报错是形状不匹配。
在交互环境中输入:
>>> import numpy as np
>>> np.array([1, 2, 3]) + np.array([1, 2])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (3,) (2,)解读:错误类型是 ValueError(值错误),信息是 operands could not be broadcast together with shapes (3,) (2,)(操作数无法按形状 (3,) 和 (2,) 进行广播)。两个数组长度不同(3 和 2),不能逐元素相加。「广播」是第 7 章的主题,现在只需记住:两个形状不兼容的数组做运算会报 ValueError。
读 NumPy 报错三步:
- 看最后一行:错误类型 + 一句话说明,形状错误的信息里一定带有
shapes (...)。 - 看中间的行:出错的是哪条语句、哪个文件。
- 核对参与运算的数组形状:用
print(数组.shape)确认。
动手实践
- 在项目根目录运行
uv run python进入交互环境,验证numpy.__version__。 - 创建你自己的身高数组
np.array([...]),打印它,再打印ndim、shape、dtype。 - 把数组每个元素减 5 并打印,验证结果仍是数组;再用 Python 列表做同样的
- 5,观察报错——这直观展示了数组与列表运算语义的区别。 - 故意让
np.array([1, 2, 3])与np.array([1, 2])相加,用「读报错三步」说出:错误类型是什么、两个操作数的形状各是什么。
常见错误
| 错误写法 | 现象 | 原因 |
|---|---|---|
np.array(1, 2, 3) | TypeError: array() takes from 1 to 2 positional arguments | array 只接受一个序列参数,应写成 np.array([1, 2, 3]) |
[1, 2, 3] + [4, 5, 6] | 结果是 [1, 2, 3, 4, 5, 6] | 列表的 + 是拼接,不是逐元素相加;要用 np.array |
np.array([1, 2, 3]) + np.array([1, 2]) | ValueError: operands could not be broadcast... | 形状不兼容,不能逐元素运算 |
import numpy 后直接用 array(...) | NameError: name 'array' is not defined | 导入简写后要用 np.array(...);或写成 from numpy import array |
numpy.array([1, 2])(大写 N) | ModuleNotFoundError: No module named 'numpy' | 包名是小写 numpy;先确认已 pip install numpy |
章末练习
基础
- 写一段代码:创建数组
[10, 20, 30, 40, 50],分别打印它的ndim、shape、dtype。 - 创建二维数组
[[1, 2, 3], [4, 5, 6]],打印形状并说明它代表几行几列。 - 验证安装:用一行命令输出你本机 NumPy 的版本号。
提高
- 用列表
[1, 2, 3]分别做[1, 2, 3] * 2和np.array([1, 2, 3]) * 2,打印两个结果,并解释为什么不同。 - 创建数组
np.array([1.0, 2, 3])(混入一个小数),打印它的dtype,再解释为什么整个数组变成浮点型。
挑战
- 不运行代码,预测
np.array([1, 2, 3]).mean()的输出,再运行验证;然后用列表完成同样任务(需要循环或sum(lst)/len(lst)),比较两种写法。 - 用
np.arange(1_000_000)创建 100 万个数,执行+1运算;用列表推导式完成同样的+1,用time模块分别计时,感受向量化的速度差异(提示:列表版本大约慢几十倍)。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
- NumPy 的核心对象是什么?
- A.
list - B.
ndarray - C.
dict - D.
Series
- A.
- NumPy 社区约定的导入写法是?
- A.
import numpy - B.
import numpy as np - C.
from numpy import * - D.
import np
- A.
np.array([1, 2, 3]).shape的结果是?- A.
3 - B.
(3,) - C.
(1, 3) - D.
[3]
- A.
np.array([1.5, 2]).dtype的结果是?- A.
int64 - B.
float64 - C.
object - D.
str
- A.
np.array([[1, 2], [3, 4]])的ndim是?- A.
1 - B.
2 - C.
4 - D.
(2, 2)
- A.
np.array([1, 2, 3]) + 10的结果是?- A.
[11, 12, 13](列表) - B.
[1, 2, 3, 10] - C.
[11 12 13](数组) - D. 报错
- A.
- 数组与列表的一个关键区别是?
- A. 数组可以存放不同类型
- B. 数组要求元素类型一致,且运算向量化
- C. 列表支持索引,数组不支持
- D. 没有区别
np.array([1, 2, 3]) + np.array([1, 2])会?- A. 返回
[2, 4, 3] - B. 返回
[2, 4] - C. 报
ValueError - D. 返回列表
- A. 返回
- 下列哪个是查看数组元素个数的属性?
- A.
len(方法) - B.
shape - C.
ndim - D.
size
- A.
- 关于向量化,正确的说法是?
- A. 必须用 for 循环处理数组
- B. 一次运算作用于整个数组,内部用编译代码批量执行
- C. 只有列表才支持向量化
- D. 向量化会让程序更慢
