本系列是《NumPy 速通》的配套章节。
调整数组的"长相"——重塑、展平、转置、增删维度,是数据处理和喂给模型的必经步骤。核心心法:shape 变了,但底层数据(和顺序)没变。
reshape —— 重塑形状
不改变元素个数,只改变排列方式。注意顺序:按行优先(C 顺序)逐行填充:
import numpy as np
arr = np.arange(12) # [0 1 2 3 4 5 6 7 8 9 10 11]
arr.reshape(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
arr.reshape(4, 3)
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]
arr.reshape(2, 6) # 2 行 6 列
-1 让 NumPy 自动算维度
arr.reshape(2, -1) # 自动算出 6 列 → (2, 6)
arr.reshape(-1, 3) # 自动算出 4 行 → (4, 3)
arr.reshape(-1) # 展平成一维(等价的另一种写法)
-1 只能出现一次(否则无法确定)。
⚠️ 元素总数必须一致
np.arange(12).reshape(3, 5) # ❌ ValueError:12 无法变成 3×5=15
报错 cannot reshape array of size 12 into shape (3,5)。reshape 前先用 arr.size 确认。
flatten 与 ravel —— 展平成一维
arr = np.array([[1, 2], [3, 4]])
arr.flatten() # [1 2 3 4] 返回副本(新内存)
arr.ravel() # [1 2 3 4] 返回视图(尽量共享内存,省内存)
区别:
flatten():总是副本,改它不影响原数组ravel():尽量返回视图(共享内存,快);仅在不得已时才复制
r = arr.ravel()
r[0] = 99
print(arr) # [[99 2] [3 4]] ⚠️ 原数组被改了(ravel 是视图)!
⚠️ 想展平后安全修改,用
flatten();只读统计用ravel()(更快更省内存)。
转置 —— 行列互换
arr = np.array([[1, 2, 3],
[4, 5, 6]])
arr.T # [[1 4] [2 5] [3 6]] 行列互换,(2,3)→(3,2)
np.transpose(arr) # 等价写法
arr.transpose() # 也是等价写法
一维数组转置没变化([1 2 3].T 还是 [1 2 3])。
⚠️ 灵魂警告:转置是视图(零拷贝、共享内存),不是副本!
t = arr.T; t[0,0] = 99会改原数组。要独立副本用arr.T.copy()。另外转置不"搬运数据",只是改了
strides(步长),所以转置是 O(1) 零成本——这也是 NumPy 高效的原因之一。
多维转置 / 轴重排(进阶)
arr3d = np.arange(24).reshape(2, 3, 4)
arr3d.transpose(2, 1, 0) # 指定轴的排列顺序
arr3d.swapaxes(0, 2) # 交换两个轴
深度学习里 (batch, height, width, channel) → (batch, channel, height, width) 就靠 transpose。
增加 / 删除维度
newaxis / expand_dims —— 加维度
arr = np.array([1, 2, 3]) # shape (3,)
arr[np.newaxis, :] # (1, 3) 变成"一行"
arr[:, np.newaxis] # (3, 1) 变成"一列"
np.expand_dims(arr, 0) # (1, 3) 等价于第一种
np.expand_dims(arr, 1) # (3, 1) 等价于第二种
💡
np.newaxis加长度为 1 的维度,常用于配合广播(第 8 章):(3,)没法直接和(5,3)做"每列"运算,但(3,1)可以。这是数据变形最常用的技巧之一。
squeeze —— 删掉长度为 1 的维度
arr = np.array([[[1, 2, 3]]]) # shape (1, 1, 3)
np.squeeze(arr) # [1 2 3] 删掉所有长度为 1 的维度
np.squeeze(arr, axis=0) # (1, 3) 只删指定轴
arr.squeeze() # 方法形式
squeeze 常用来去掉"多余的 1",比如模型输出 (1, 1, 10) 变成 (10,)。
⚠️
squeeze默认删所有长度为 1 的轴。想精准删哪个用axis=指定。删完 shape 变了对不上号,报错前先确认。
组合实战:把一维变"每列"
最常见的需求:(3,) 想按"每一列"去广播,先升维再运算:
col = np.array([10, 20, 30])
col[:, np.newaxis] # (3, 1) 每列一个
# [[10]
# [20]
# [30]]
这样就能和 (5, 3) 的表格做"每列加不同值"(见第 8 章广播)。
小结
| 操作 | 作用 | 返回副本? |
|---|---|---|
reshape |
改形状(数量不变) | 视图 |
flatten |
展平一维 | 副本 |
ravel |
展平一维 | 视图 |
.T / transpose |
转置 / 重排轴 | 视图 |
newaxis / expand_dims |
加长度为 1 的维度 | 视图 |
squeeze |
删长度为 1 的维度 | 视图 |
牢记:reshape、transpose、ravel 都是视图,改它们会污染原数组——要独立副本就 .copy()。
下一章:对数组每个元素做数学函数(ufunc)。
上一篇:第 4 章 数组运算 | 下一篇:第 6 章 通用函数