np.random.shuffle只对一维数组原地洗牌,多维时默认按行洗牌且返回none;np.random.choice需明确replace参数和输入类型,推荐用default_rng保证可重现性。

NumPy 的 np.random.shuffle 和 np.random.choice 能高效完成原地洗牌与带/不带放回采样,但必须注意数组维度、随机状态控制和视图/副本行为——否则极易得到重复结果或意外修改原始数据。
为什么 np.random.shuffle 有时没效果?
它只对一维数组做原地洗牌;对多维数组,默认沿 axis=0 洗牌行(不是打乱所有元素),且返回 None。若误用于二维数组又想打乱全部元素,会发现“好像没变”。
- 一维:直接用
np.random.shuffle(arr),arr被就地修改 - 二维:若要打乱所有元素,先用
arr.ravel()或arr.flatten()得到一维视图/副本,再 shuffle;但注意ravel()返回视图,修改会影响原数组,flatten()返回副本则不会 - 切记不能写成
arr = np.random.shuffle(arr)—— 因为它返回None,这会导致arr变成None
np.random.choice 怎么选才不重复也不越界?
它本质是按索引采样,不是直接对数组内容操作。常见错误是传入非整数数组或忽略 replace 参数含义。
- 基础用法:
np.random.choice(a, size, replace=True/False),其中a可以是整数(表示从0到a-1采样)或一维数组(从其元素中采样) - 要无放回采样(即不重复),必须设
replace=False,且size不能大于a的长度,否则报错ValueError: Cannot take a larger sample than population when 'replace=False' - 若
a是数组,采样结果类型与a.dtype一致;若a是整数,结果默认为int64 - 性能提示:当
size接近a长度且replace=False时,内部使用 Fisher-Yates,比先 shuffle 再切片稍慢;此时可考虑先shuffle再取前size个
如何保证多次运行结果可复现?
全局随机种子(np.random.seed())在 NumPy 1.17+ 已被标记为 legacy,推荐使用独立的随机数生成器实例(Generator),避免干扰其他库或后续代码。
- 创建可复现实例:
rng = np.random.default_rng(seed=42) - 用它调用方法:
rng.shuffle(arr)、rng.choice(...) - 不要混用:
np.random.shuffle()和rng.shuffle()使用不同底层状态,混用会导致不可预测行为 - 如果必须兼容旧代码,至少确保全局
seed设置在所有随机操作之前,且不被中间其他库调用覆盖
最易被忽略的是多维数组 shuffle 的语义差异和 choice 输入类型隐式转换——比如传入一个 list 会被自动转成 ndarray,但若含混合类型,可能变成 object dtype,导致 choice 行为异常;动手前先检查 arr.dtype 和 arr.ndim。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











