np.random.shuffle() 是原地操作,直接修改输入数组且不返回新数组;而 np.random.permutation() 返回新数组,不改变原数组,二者语义本质不同。

np.random.shuffle() 是原地操作,改完就没了
它直接修改你传入的数组,不返回新数组——这点和 random.shuffle() 一模一样,但和 np.random.permutation() 完全相反。如果你写了 shuffled_arr = np.random.shuffle(arr),shuffled_arr 会是 None,而 arr 已被悄悄打乱。
- 必须确保输入是 NumPy 数组(
ndarray),传入 Python 列表会报TypeError: 'list' object is not callable - 对二维数组只打乱“行顺序”,每行内部不动;想打乱列?得自己索引重排,比如
arr[:, np.random.permutation(arr.shape[1])] - 不能用于只读数组(
arr.flags.writeable = False),否则抛ValueError: assignment destination is read-only
permutation() 不动原数组,适合需要保留原始顺序的场景
np.random.permutation() 返回一个新数组(或新索引),原数组纹丝不动。这是它和 shuffle() 最本质的区别——不是“要不要副本”的风格问题,而是语义级差异。
- 传入一维数组 → 返回打乱后的新数组
- 传入整数
n→ 返回0到n-1的随机排列,常用来生成洗牌索引:idx = np.random.permutation(len(x)),再用x[idx]和y[idx]同步打乱特征与标签 - 传入多维数组 → 只沿 axis=0 洗牌(同
shuffle),但依然不改原数组
同时打乱 X 和 y?别用两次 shuffle,用 permutation 索引
常见错误:分别对特征数组 X 和标签数组 y 各调一次 np.random.shuffle(X) 和 np.random.shuffle(y) —— 这俩完全独立,对应关系当场崩坏。
- 正确做法:生成一次随机索引,复用它:
idx = np.random.permutation(len(X)),然后X_shuffled = X[idx],y_shuffled = y[idx] - 如果非要用
shuffle,只能先拼接再拆开(仅限同长度、可垂直堆叠):data = np.column_stack([X, y])→np.random.shuffle(data)→ 再切分,但有类型转换风险(比如X是 float,y是 int,拼成 object 类型)
随机状态没设好,结果就不可复现
NumPy 的随机函数默认依赖全局随机状态,不同版本、不同平台甚至不同线程下行为可能漂移。调试模型或写测试时,这会让你怀疑人生。
- 务必显式设置种子:
np.random.default_rng(42)(推荐,NumPy 1.17+)或旧式np.random.seed(42) - 更稳妥的做法:用独立随机器实例,避免全局污染:
rng = np.random.default_rng(42),然后用rng.shuffle(arr)或rng.permutation(...) - 注意:
np.random.shuffle()和np.random.permutation()都受当前全局状态影响,除非你传入了Generator实例
shuffle,多敲三个字符用 permutation 索引,稳得多。










