最可靠方式是使用numpy.random.Generator.choice:需先创建rng = np.random.default_rng(seed)实例,再调用rng.choice(arr, size, replace=False),它性能优、可复现、线程安全,且不支持隐式多维输入,须手动处理轴向抽样或展平。

用 numpy.random.Generator.choice 是当前最可靠的方式
NumPy 1.17+ 弃用了旧的 numpy.random.choice(来自全局 np.random 模块),推荐使用基于 Generator 的新接口。它默认就是无放回抽样,且底层用的是 Fisher-Yates 洗牌变体,性能好、可复现、线程安全。
常见错误是直接调用 np.random.choice(a, size, replace=False) —— 这在 NumPy ≥1.25 中会触发 DeprecationWarning,且无法控制随机种子粒度。
- 必须先创建
Generator实例:rng = np.random.default_rng(seed=42) - 抽样时传入数组本身(而非长度):
rng.choice(arr, size=10, replace=False),arr可以是 1D 数组或任意可索引序列 - 若
arr是多维,需先展平或用np.take+ 随机索引配合,choice不支持直接对高维数组做轴向无放回采样
抽样数量接近数组长度时要注意内存和性能
当 size 接近 len(arr)(比如 > 70%),replace=False 内部会退化为洗牌后切片(即先 shuffle 整个数组再取前 size 个),这会额外分配等长内存并修改原数组副本。
如果你只想要“打乱后取前 k 个”,更高效的做法是直接 shuffle 再切片:
立即学习“Python免费学习笔记(深入)”;
rng = np.random.default_rng(42) shuffled = arr.copy() rng.shuffle(shuffled) sample = shuffled[:k]
这个方式避免了 choice 的中间索引映射开销,尤其在大数组、高比例采样时快 2–3 倍,且显式可控。
对二维数组按行/列无放回抽样得手动构造索引
Generator.choice 只接受一维输入,所以不能直接写 rng.choice(matrix, axis=0, replace=False) —— 这会报错 ValueError: a must be 1-dimensional。
正确做法是生成行/列索引,再用高级索引提取:
- 按行抽样(随机选 5 行):
rows = rng.choice(matrix.shape[0], size=5, replace=False); sample = matrix[rows] - 按列抽样(随机选 3 列):
cols = rng.choice(matrix.shape[1], size=3, replace=False); sample = matrix[:, cols] - 注意:这里
choice作用于整数范围,不是原始数组,所以不会触发拷贝整个数据的开销
旧代码迁移要检查 replace 默认值和 seed 行为
老写法 np.random.choice(arr, 10) 默认 replace=True;而新 Generator.choice **没有默认 replace 值**,必须显式传参,否则报 TypeError。
另外,np.random.seed() 全局影响所有后续调用,但 default_rng(seed) 是局部实例,互不干扰——这点在多线程或单元测试中特别关键,漏掉会导致随机性污染。
最容易被忽略的是:如果原逻辑依赖 np.random.choice 对非一维数组的隐式 ravel 行为(比如传入 list of lists),新接口会直接报错,必须提前 np.asarray(...).ravel()。


















