📑 本页目录(点开跳转)
附录A · 速查
⏱ 26 分钟 | ⭐ 报错原文抄进搜索框查不到?这一页按「你看到的那句话」反查原因
🎯 一句话
这一页不讲道理,只做两件事:把常用 API 按「你想干什么」排好,把报错原文按「你看到什么」排好。
正文各章负责让你懂,这一页负责让你快。所有报错原文都是本机(numpy 2.4.6)真触发出来的,可以直接 Ctrl+F。
🧩 一、API 速查:按用途排,不按字母排
造数组
| 你想干什么 | 写法 |
|---|---|
| 从列表来 | np.array([1,2,3]) |
| 全 0 / 全 1 / 未初始化 | np.zeros(n) · np.ones(n) · np.empty(n) |
| 等差 | np.arange(0,10,2)(不含尾) · np.linspace(0,1,11)(含尾) |
| 和别人同形状 | np.zeros_like(a) · np.ones_like(a) · np.full_like(a, 7) |
| 单位阵 / 对角 | np.eye(3) · np.diag([1,2,3]) |
⚠️ np.empty 不是全 0,是没初始化的内存 —— 里面是上一个用户留下的字节。
改形状
| 你想干什么 | 写法 | 视图? |
|---|---|---|
| 换形状 | a.reshape(2,-1) |
⚠️ 尽量视图,不行悄悄拷贝 |
| 换形状但不许拷贝 | a.shape = (2,-1) |
✅ 做不到就报错 |
| 压平 | a.ravel() |
✅ 尽量视图 |
| 压平并保证独立 | a.flatten() |
❌ 永远拷贝 |
| 转置 | a.T · a.transpose(2,0,1) |
✅ 只改说明书 |
| 加一个长度 1 的轴 | a[:, None] · np.expand_dims(a,1) |
✅ |
| 去掉长度 1 的轴 | a.squeeze() |
✅ |
| 拼接 | np.concatenate([a,b], axis=0) · np.stack([a,b]) |
❌ 都拷贝 |
聚合
| 你想干什么 | 写法 |
|---|---|
| 求和 / 均值 / 标准差 | a.sum(axis=0) · a.mean(axis=1) · a.std() |
| 最值 | a.max() · a.min() |
| 最值在哪 | a.argmax() · np.unravel_index(a.argmax(), a.shape)(多维) |
| 忽略 NaN | np.nansum · np.nanmean · np.nanmax |
| 累积 | a.cumsum() · a.cumprod() |
| 保住维度好广播 | a.sum(axis=1, keepdims=True) ⭐ |
| 有没有 / 是不是全部 | a.any() · a.all() |
| 计数 | np.count_nonzero(mask) · np.bincount(idx) |
⭐ keepdims=True 是减少广播出错最有用的一个参数:a - a.mean(axis=1, keepdims=True) 一次就对。
挑元素
| 你想干什么 | 写法 | 视图? |
|---|---|---|
| 切一块 | a[1:3, ::2] |
✅ |
| 按下标列表挑 | a[[0,2,5]] |
❌ 拷贝 |
| 按条件挑 | a[a > 5] |
❌ 拷贝 |
| 只要下标 | np.flatnonzero(mask) · np.where(mask) |
|
| 三元选择 | np.where(cond, x, y) |
|
| 按条件赋值 | a[a < 0] = 0 |
就地改 |
| 夹住范围 | np.clip(a, 0, 1) |
随机
| 你想干什么 | 写法 |
|---|---|
| ⭐ 建生成器(推荐) | rng = np.random.default_rng(42) |
| 均匀 / 正态 / 整数 | rng.random(n) · rng.normal(0,1,n) · rng.integers(0,10,n) |
| 打乱 / 抽样 | rng.shuffle(a) · rng.choice(a, 3, replace=False) |
⚠️ np.random.seed() 那一套是全局状态,任何库都能改它。新代码一律用 default_rng(详见 10 章)。
🧯 二、⭐ 报错原文 → 原因(全部真触发过)
用法:把你看到的报错开头几个词在这一节 Ctrl+F。
operands could not be broadcast together with shapes (3,4) (3,5)
广播失败。 从右往左对齐后,有一对轴既不相等、也没有一个是 1。
→ 打印 a.shape, b.shape 对着 03 章的三条规则 逐轴比。
最常见的真实原因:忘了 keepdims=True,或者某个轴被 squeeze 掉了。
setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions.
你喂了一个「锯齿」嵌套列表(各行长度不同),比如 np.array([[1,2],[3]])。
→ 要么补齐成矩形,要么用 dtype=object(但那样就没有向量化了)。
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
你把一个数组当成了 True/False。 最常见的三种写法:
if arr: ... # ❌
if arr > 0: ... # ❌
if (a > 3) and (a < 8): # ❌ and/or 对数组无效
→ 分别改成 if arr.any():、if (arr > 0).all():、(a > 3) & (a < 8)。
⚠️ 用 & | 时括号不能省,因为它们的优先级比比较运算符高。
To change to a dtype of a different size, the last axis must be contiguous
.view() 换 dtype 时数组不连续。 通常是转置或跳步切片之后。
→ np.ascontiguousarray(a) 先压实一份。机制见 05 章。
cannot reshape array of size 12 into shape (5,3)
元素个数对不上:12 ≠ 15。
→ 用 -1 让它自己算一个轴:a.reshape(-1, 3)。
index 5 is out of bounds for axis 0 with size 3
下标越界。 注意它明确告诉了你是哪个轴、那个轴多长。
boolean index did not match indexed array along axis 0; size of axis is 5 but size of corresponding boolean axis is 2
布尔掩码长度和被索引的轴对不上。 通常是掩码在数组变形之后才算的,或者算掩码时用错了轴。
could not convert string to float: np.str_('a')
astype(float) 撞上了非数字字符串。
→ 用 pd.to_numeric(..., errors="coerce") 或先 np.isreal 筛一遍。
RuntimeWarning: overflow encountered in exp
⚠️ 这是警告不是报错,程序会带着 inf 继续跑。 阈值取决于精度:
| dtype | exp(88) |
exp(89) |
exp(90) |
exp(709) |
exp(710) |
|---|---|---|---|---|---|
| float32 | 1.65e+38 |
inf |
inf |
inf |
inf |
| float64 | 正常 | 正常 | 1.22e+39 |
8.22e+307 |
inf |
⭐ float32 训练时这个坑近在咫尺,float64 要到 710 才炸。
解法永远是先减最大值:np.exp(z - z.max())。详见 09 章 log 域运算。
📋 三、视图还是拷贝
| 操作 | 结果 | 为什么 |
|---|---|---|
a[1:3] · a[::2] · a[:, 0] |
✅ 视图 | 偏移等差,能写成一组 strides |
a.T · a.transpose() |
✅ 视图 | 只把说明书倒过来 |
a.reshape(...) |
⚠️ 尽量视图 | 不连续时悄悄拷贝,不报错 |
a.ravel() |
⚠️ 尽量视图 | 同上 |
a.flatten() |
❌ 永远拷贝 | 它的契约就是给你一份独立的 |
a[[0,2,5]] |
❌ 拷贝 | 任意顺序,写不出等差 strides |
a[a > 5] |
❌ 拷贝 | 长度要到运行时才知道 |
a.astype(...) |
❌ 拷贝 | 除非 copy=False 且 dtype 没变 |
np.concatenate · np.stack |
❌ 拷贝 | 要开新内存 |
⭐ 判据永远用 np.shares_memory(a, b),⚠️ 不要用 b.base is a ——
.base 指向的是最终持有内存的那个、不是上一层(05 章第三节有实测)。
🚦 四、「以为对,其实错」
import numpy as np
# ① == 返回的是数组,不是 bool
print(np.array([1,2]) == np.array([1,3])) # [ True False]
# → 要一个 bool 就用 np.array_equal(a, b)
# ② NaN 不等于自己
print(np.nan == np.nan) # False
# → 判 NaN 只能用 np.isnan(x)
# ③ 整数相除会变浮点
r = np.array([5]) / np.array([2])
print(r, r.dtype) # [2.5] float64
# → 要整除用 //
# ④ dtype 会悄悄提升
print((np.ones(1, dtype=np.int8) + np.ones(1, dtype=np.int64)).dtype) # int64
# ⑤ ⚠️ 但同类型整数溢出【没有任何警告】
a = np.array([100], dtype=np.int8)
print(a + a) # [-56] ← 一声不吭
⑤ 是这一页最值得记的一条:int8 的 100 + 100 得到 -56,连个 RuntimeWarning 都没有。
np.exp 溢出还会警告你一声,整数溢出完全静默。详见 08 章。
🔗 这一章连到哪里
| 相关的地方 | 为什么 |
|---|---|
| 05 · 内存布局与 stride | 「视图还是拷贝」那张表背后的唯一规则:能不能写成一组 strides |
| 08 · 整数 dtype 的真相 | 静默溢出那条的完整版,含怎么防 |
| 09 · log 域运算 | exp 溢出表背后的数值稳定性套路 |
| 11 · 从 NumPy 到 PyTorch | 这些 API 在 torch 里叫什么 |
| ML 基础 · 附录C 手撕代码速查 | 面试要手写的那十道题,用的就是这一页的 API |
✅ 检查点
a.ravel()和a.flatten()差在哪?- 看到
The truth value of an array with more than one element is ambiguous,三种常见写法各怎么改? np.exp(90)在 float32 和 float64 下分别是什么?int8的100 + 100等于几?会不会警告你?- 判断两个数组是不是共享内存,该用什么?为什么不用
.base?
👀 答案
ravel()尽量返回视图(不连续时才拷贝),flatten()永远拷贝 —— 它的契约就是给你一份独立的。if arr:→if arr.any():(或.all());if arr > 0:→if (arr > 0).all():;if (a>3) and (a<8):→(a > 3) & (a < 8),⚠️ 括号不能省,&的优先级比比较运算符高。- float32 下是
inf(exp(89)就炸了,exp(88)还有1.65e+38);float64 下是1.22e+39,要到exp(710)才inf。所以 float32 训练时这个坑近在咫尺。 -56,而且一句警告都没有。⚠️np.exp溢出还会给RuntimeWarning,整数溢出完全静默。- 用
np.shares_memory(a, b)。不用.base是因为它指向的是最终持有那块内存的数组、不是上一层 ——a.T.base is a会给False,但它们确实共享内存。
🛑 可以停在这里
⚡ 走神救援
⭐ 这一页是查的不是读的,但有几条值得直接背下来。
报错反查:广播对不齐要从右往左逐轴看,⭐ 最常见的真凶是忘了
keepdims=True;「真值不明确」是把数组当成了布尔量,三种改法分别是.any()、.all()、把and换成&——⚠️ 括号不能省,位运算的优先级比比较运算符高;「最后一维必须连续」是换 dtype 撞上了不连续,压实一份即可。⭐ 视图还是拷贝只有一条规则:能写成一组等差步长的就是视图。 基础切片和转置是视图;⭐ 花式索引(偏移任意)和布尔掩码(长度运行时才知道)必然拷贝;
reshape尽量给视图、不行就悄悄拷贝且不报错,而flatten永远拷贝。⚠️⭐ 判断共享内存一律用
np.shares_memory,别用.base——它指向最终持有内存的那个,而不是上一层,所以转置之后拿.base去比会得到False。数值上三条最容易栽:
nan不等于自身(判它只能用专门的函数);==返回的是数组不是布尔值;⭐⭐ 最要命的是整数溢出完全静默——小整数类型加一下就绕回负数,连个警告都没有,而浮点溢出好歹还给你一句警告。⭐ 顺带记住指数函数的两个阈值:单精度到八十几就变成无穷,双精度要到七百多——所以那个「
exp(90)会溢出」的直觉在双精度下是错的。⭐ 解法永远是先减掉最大值。
下一节 👉 回到板块索引