NumPy 函数速查表 - NumPy 常用命令与数组操作大全
这套速查面向常用 Python 处理数组的开发者,无论做数据分析、几何计算还是给模型做输入预处理都会用到:从 np.array/np.zeros 建数组,到索引起始值切片取数据、reshape 变换形状、sum/mean 做统计,再到 a @ b 做矩阵乘。与纯 API 手册不同,条目按"建数组→取值→变形→算账→存盘"的实战链路组织。读完应能想到每个阶段用哪个函数,并避开广播和视图/副本最容易踩的那几个坑。
典型使用场景
面向做数据清洗、统计计算与数值实验的工程师,尤其是从 pandas 或 R 迁过来需要先建立「ndarray 语义」的人。NumPy 的性能来自向量化,代价是形状与广播规则比 Python 列表严格得多。本表覆盖四组:数组创建(array / zeros / arange / linspace / 随机数)、索引与切片(布尔掩码、 Fancy indexing、多维切片)、形状变换(reshape / flatten / T / concatenate / split)、以及数学统计与广播和存取盘(sum / mean / std / dot / unique / save / loadtxt)。最该先掌握的两条规则是:reshape 返回视图而 flatten 返回副本(就地改会互相影响),以及形状不兼容时广播会报错或静默产生意外结果。
数组创建 9
np.array([1, 2, 3])np.zeros((3, 4))np.ones((2, 3))np.arange(0, 10, 2)np.linspace(0, 1, 5)np.eye(3)np.random.rand(3, 3)np.random.randn(3, 3)np.random.randint(0, 10, (2, 3))索引与切片 6
a[0]a[1:3]a[a > 5]a[[0, 2, 4]]a[1:3, 2:4]np.where(a > 5, a, 0)形状变换 8
a.shapea.reshape(2, 3)a.flatten()a.Tnp.concatenate([a, b], axis=0)np.vstack([a, b])np.hstack([a, b])np.split(a, 3)数学与统计 10
a.sum()a.mean()a.std()a.min() / a.max()a.argmin() / a.argmax()a.cumsum()np.dot(a, b)a @ bnp.sort(a)np.unique(a)广播与保存 7
a + 1a * 2a + b(形状兼容即可)np.save("data.npy", a)np.load("data.npy")np.savetxt("data.csv", a, delimiter=",")np.loadtxt("data.csv", delimiter=",")参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
np.array([1, 2, 3]) | 从列表创建数组;dtype 决定元素类型,缺省按值推断 | np.array([1, 2, 3]) |
np.zeros((3, 4)) | 按形状创建全零数组;注意参数是元组,写成 (3, 4) 而不是 3, 4 | np.zeros((3, 4)) |
np.ones((2, 3)) | 按形状创建全 1 数组,常用作掩码或权重初值 | np.ones((2, 3)) |
np.arange(0, 10, 2) | 等差数列,不含终点;步长为浮点时会因精度产生意外的结束值 | np.arange(0, 10, 2) |
np.linspace(0, 1, 5) | 在闭区间内均分 5 个点(含两端),画函数曲线时不会漏端点 | np.linspace(0, 1, 5) |
np.eye(3) | 生成 3x3 单位矩阵,线性代数运算的基础件 | np.eye(3) |
np.random.rand(3, 3) | 生成 [0, 1) 均匀分布的随机数矩阵 | np.random.rand(3, 3) |
np.random.randn(3, 3) | 生成标准正态分布随机数矩阵;与 rand 的区别是分布不同而非取值范围 | np.random.randn(3, 3) |
np.random.randint(0, 10, (2, 3)) | 生成指定形状的随机整数,左闭右开 | np.random.randint(0, 10, (2, 3)) |
a[0] | 按维度取下标,返回的仍可能是数组而非标量,取决于维度 | a[0] |
a[1:3] | 切片视图,不复制数据;改动切片会改到原数组 | a[1:3] |
a[a > 5] | 布尔掩码筛选,返回副本,是过滤数据最直接的写法 | a[a > 5] |
a[[0, 2, 4]] | Fancy indexing 用索引数组取任意元素,返回副本 | a[[0, 2, 4]] |
a[1:3, 2:4] | 多维切片,先切第一个维度再切第二个 | a[1:3, 2:4] |
np.where(a > 5, a, 0) | 三参数形式按条件逐元素取值,是向量化条件赋值的核心 | np.where(a > 5, a, 0) |
a.shape | 查看形状;比用 len 判断多维数组是否可靠得多 | a.shape |
a.reshape(2, 3) | 返回视图,不复制数据;改视图元素会影响原数组,无法原地改形状 | a.reshape(2, 3) |
a.flatten() | 返回一维副本,与 reshape 的最大差别就在是否复制 | a.flatten() |
a.T | 转置视图,交换行列;一次矩阵乘法写错方向常源于此 | a.T |
np.concatenate([a, b], axis=0) | 沿指定轴拼接,数组形状除拼接轴外必须完全一致 | np.concatenate([a, b], axis=0) |
np.vstack / np.hstack | 按行/列堆叠,是 concatenate 在两个轴上的简写 | np.vstack([a, b]) |
np.split(a, 3) | 把数组切成 3 份;返回列表,各份按原顺序排列 | np.split(a, 3) |
a.sum() / a.mean() | 默认对所有元素聚合;指定 axis 可沿某一维折叠并保持其它维 | a.sum() |
a.std() | 标准差,默认总体口径;做数据归一化时最常用 | a.std() |
a.argmin() / a.argmax() | 返回极值所在的扁平索引;二维数组要配合 unravel_index 才有意义 | a.argmin() / a.argmax() |
a.cumsum() | 累积和,做累计分布、差分、滚动统计的基础 | a.cumsum() |
np.dot(a, b) / a @ b | 点积与矩阵乘法,两种等价写法;形状必须满足矩阵乘法规则 | np.dot(a, b) |
np.sort(a) | 返回排序后的副本,不改变原数组;就地排序用 a.sort() | np.sort(a) |
np.unique(a) | 去重并升序排序,是统计取值分布最省事的一行 | np.unique(a) |
a + 1 / a * 2 | 广播运算,标量自动扩展到每个元素,无需写循环 | a + 1 |
a + b(形状兼容即可) | 广播要求从右对齐且逐维兼容(一为 1 或相等),否则报 broadcast 错误 | a + b(形状兼容即可) |
np.save("data.npy", a) | 保存为 .npy 二进制格式,保留 dtype 与形状,读取无损且快 | np.save("data.npy", a) |
np.load("data.npy") | 读回 .npy;返回的是数组而不是路径(与 np.load 的其它用法易混) | np.load("data.npy") |
np.savetxt(..., delimiter=",") | 导出为纯文本 CSV,可读但丢失 dtype 信息,且大文件慢 | np.savetxt("data.csv", a, delimiter=",") |
np.loadtxt("data.csv", delimiter=",") | 读回 CSV;指定 dtype 能避免整数被读成 float | np.loadtxt("data.csv", delimiter=",") |
易错点与避坑指南
现象改了 reshape 结果的元素,原数组也跟着变了。
原因reshape 在数组连续时返回视图,只有必要时才复制。
处置需要独立副本时先 copy() 或改用 flatten();要确认是否共享可看 base 属性。
现象两个数组相加报 operands could not be broadcast。
原因形状在某一维既不相等也不为 1;广播是逐维从右对齐匹配的。
处置先统一维度(a.reshape(-1, 1))或用 np.broadcast_to 显式扩展;别急着加循环。
现象结果形状变成 (N, 1) 而不是预期的 (N,),索引时行为诡异。
原因标量与数组运算、或 a[:, None] 切片引入的新维度导致轴没有消除。
处置用 a.shape 核对每一维;需要降到一维时用 a.ravel() 或 a.flatten()。
现象np.arange 生成的长度比预期多一个或少一个。
原因arange 不含终点,且浮点步长会累积误差,末值可能越过终点。
处置需要确定的点数改用 np.linspace(0, 1, 5),它按点数反推步长。
现象np.zeros(3, 4) 报 TypeError。
原因这是函数调用不是元组字面量,Python 会当成三个实参。
处置写成 np.zeros((3, 4)),用逗号传元组时必须带括号。
现象取 a[0] 得到一整行而不是一个数。
原因a 是二维数组,取第一维下标返回的是一行。
处置明确降维:a[0, 0] 或 a[0][0],或先 a.ravel() 再索引。
现象随机结果每次运行都不一样,无法复现实验。
原因直接使用全局随机状态,没有设置种子。
处置在脚本开头固定种子再生成,并记录版本号;对比实验时这步不能省。
现象np.load 返回的是 MemMap 而不是数组,改动意外写回了磁盘。
原因np.load 对 .npy 默认使用 mmap 模式共享内存映射。
处置需要普通数组时加 mmap_mode=None(默认即为普通读取时检查返回值类型)。
排障路径
1先看清每个数组的形状与类型
print([(x.shape, x.dtype) for x in arrs])形状与 dtype 是九成广播与索引问题的根因。
2检查是否共享底层内存
print(arr.reshape(-1).base)base 非 None 说明是视图,改动会互相影响。
3复现广播错误的具体维度
print(np.broadcast(a, b))广播失败时会在这里直接暴露不兼容的轴。
4确认归一化后的取值范围
print((a - a.mean()) / a.std())标准差为 0 的列会产生 NaN,需要先剔除。
5核对读回文件的形状与 dtype
print(np.load("data.npy").shape)与保存前对比,确认没有被压缩或转换。
6确认 NumPy 版本
python -c "import numpy; print(numpy.__version__)"跨版本行为差异(尤其是随机数与默认 dtype)是环境问题高发区。
命令示例
视图 vs 副本:切片与花式索引的差别
a = np.arange(12).reshape(3, 4)
# 切片返回视图,改它会影响原数组
a[1:3, 2:4] = -1
# 花式索引返回副本,改它不影响原数组
b = a[[0, 2]]
b[0, 0] = 99
# flatten 永远是副本
c = a.flatten()
c[0] = 100同一份数据用不同取法拿到的东西,身份完全不同:对切片赋值会静默改到原数组的共享内存,对花式索引或 flatten 的结果赋值则只改副本。要「读」就随便切,要「改之前先复制」就显式 a.copy()。
布尔索引 + np.where 做阈值筛选
a = np.arange(10)
hot = a[a > 5] # 只保留大于 5 的元素
clamped = np.where(a > 5, a, 0) # 大于 5 保留,否则置 0
b = np.array([[1, 9], [7, 3]])
rows = b[b[:, 0] > 5] # 按条件挑行
count = int((a > 5).sum()) # 统计超阈值的个数掩码求值的前提是数组是一维或掩码与被选维度长度一致;对二维数组写 a[a > 5] 会先把整块摊平成一维,再取符合条件的元素,形状悄悄变了。二维场景要挑行或挑列,就得先取某一列再比较。
广播:形状不同的数组逐元素运算
a = np.arange(6).reshape(2, 3)
b = np.array([10, 20, 30]) # 形状 (3,)
c = a + b # (2,3) + (3,) → (2,3),按列广播
d = a * 2
# 维度为 1 时也能广播
a = np.arange(3).reshape(3, 1)
b = np.arange(3).reshape(1, 3)
e = a + b # (3,1) + (1,3) → (3,3)广播只沿长度为 1 的维度扩展,能免掉大量 tile/repeat。当两边同维但长度都不为 1 且不相等时报 shape 错;而当长度恰好都为 1 时又不会报错,广播出的结果形状可能与直觉相反,先打印 .shape 确认。
reshape 前先算清元素总数
a = np.arange(12) # 12 个元素
a.reshape(3, 4) # 12 = 3×4
b = a.reshape(-1, 1) # -1 表示该维度自动推断
c = a.reshape(2, -1) # 另一维自动算成 6
# 元素总数不一致会直接抛错
# a.reshape(5, 5)reshape 不搬数据、只改形状描述,所以元素总数必须对得上,否则直接抛 ValueError。用 -1 让 NumPy 自己推一维,比手算除法更不容易错;真正需要改变内存布局时才用 reshape,单纯摊平用 flatten。
线性代数与去重计数
a = np.array([[1, 0], [0, 1]])
b = np.array([[2, 3], [4, 5]])
np.dot(a, b)
a @ b
# 去重并统计出现次数
vals, counts = np.unique([1, 1, 2, 3, 3, 3], return_counts=True)点积与 @ 在一维向量上结果相同,在二维矩阵上分别是内积规则与标准矩阵乘法,别混用。unique 会自动排序,需要保持原顺序时得自己排 argsort;return_counts=True 是找频次分布最快的办法,不用再套 collections.Counter。
常见坑与注意事项
- 整数数组做除法(a / b)默认得到浮点结果,这是与旧版本行为不同的地方,直接按整数截断的假设会让均值、比例类计算悄悄变错。
- a[i] 取单个元素返回的是标量而不是长度为 1 的数组,取单个元素后再用二维索引会直接越界报错;需要保持形状时用 a[i:i+1]。
- 切片返回视图,对它赋值会静默改掉原数组共享的那块内存;循环里逐块写入又没意识到这一点时,原数据被污染却毫无报错。
- shape 不兼容的广播在某一维恰好都为 1 时不会报错,而是按广播规则静默扩展,结果形状与预期相反且难以察觉;做运算前先核对两边 .shape。
- np.where 返回的是新数组,对它赋值不会改到原数据;想原地修改必须显式写回 a[:] = np.where(...),漏掉赋值就是一次静默的数据丢失。
- 数组过大时 np.save / savetxt 与 np.load / loadtxt 都会把整个文件读进内存,几十 MB 就会耗尽内存;np.load 可配合 mmap_mode 惰性读取,纯 CSV 文本格式则不含 dtype 信息,loadtxt 需自己指定。
提示
- NumPy 数组是同构的,所有元素类型必须一致,混类型会自动提升。
- 广播规则:两个维度从后往前比较,相等或其中一个为 1 才能广播。
- a * b 是元素级乘法,矩阵乘法用 a @ b 或 np.dot(a, b)。
常见问题
切片拿到的数据改了原数组也跟着变,怎么避免?
关键是分清视图和副本。切片 a[1:3] 和 reshape 通常返回视图,改它就是改原数组;布尔索引 a[a > 5]、花式索引 a[[0, 2, 4]] 返回副本;flatten() 明确返回副本,改它不影响原数组;np.sort(a) 也返回排序后的新数组,想原地排序要调 a.sort()。所以只是要读,用切片零成本;要安全地修改,先显式拷贝,例如 np.array(a[1:3]) 或用 np.copy 之类方式拿到独立数据再改。
a * b 和 a @ b 计算结果一样吗?
完全不一样。a * b 是逐元素相乘,两个形状兼容的数组会按广播规则展开后一一相乘;a @ b 是矩阵乘法(等价于 np.matmul),按行乘列再求和,要求内维度吻合。一维向量与同长向量相乘时,(a * b) 得到的是逐元素积,而 a @ b 得到的是内积这个标量。要做线性代数、矩阵变换就必须用 @ 或 np.dot(a, b);只做逐元素缩放则用 a * 2 这类广播写法。
数组形状对不上又不想改原数据,拼接和变换怎么选?
改形状用 reshape(2, 3),元素总数必须一致,通常返回视图;a.T 转置交换维度,二维即行列互换,一维数组转置前后不变;a.flatten() 展平成一维并返回副本。要合并多个数组则看方向:np.concatenate([a, b], axis=0) 最通用,沿指定轴拼接,除拼接轴外其余维度必须一致,axis=0 是拼行、axis=1 是拼列;np.vstack 上下拼要求列数一致,np.hstack 左右拼要求行数一致。拆开则用 np.split(a, 3) 沿默认轴等分,不能整除会抛错。
怎么按阈值筛选数据,或者把不满足条件的值替换掉?
两条路径。布尔索引直接取子集:a[a > 5] 保留满足 a > 5 的元素,常用于阈值筛选和掩码取值,取列同理写 a[a[:, 0] > 5]]。要做条件替换而不是筛选,用 np.where(a > 5, a, 0):三参数形式下满足条件取中间那个值,否则取最后一个参数,因此能实现「大于阈值才计入、否则置零」。np.where 还能只传两个参数当作条件判断,返回满足条件的元素索引。
随机数据和等差序列该用哪个函数生成?
要规则序列就用确定性的函数:np.arange(0, 10, 2) 生成 [0, 2, 4, 6, 8] 这类等差数列,步长直接给第三个参数;np.linspace(0, 1, 5) 表示在 0 到 1 之间取 5 个等分点(含首尾)。要随机数用 np 系列:np.random.rand(3, 3) 是 0 到 1 的均匀分布,np.random.randn(3, 3) 是标准正态分布,np.random.randint(0, 10, (2, 3)) 生成 0 到 10 之间的 2×3 随机整数。结构性占位数组则用 np.zeros((3, 4))、np.ones((2, 3)) 和 np.eye(3)。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。