HOWTO · NumPy
NumPy Shuffle 两个数组
Python 中可以使用三种主要方法对两个对应的数组进行 shuffle,分别是 sklearn.utils.shuffle() 函数、numpy.random.shuffle() 函数和 numpy.random.permutation() 函数。
本页内容
同时打乱两个相关数组,指的是让它们的行按相同顺序改变。如果一个数组中的第 i 行描述另一个数组中的第 i 行,例如特征行及其标签,那么两个数组必须使用同一个排列。分别打乱它们会破坏这种对应关系。下面的示例使用一个两列特征数组和一个标签数组;每行中相匹配的值能直观显示这种对应关系。
同时打乱两个数组并保持对应行对齐
对两个数组应用同一个行顺序。每个输入数组的第一维长度必须相同。对于包含多列的数组,共同的顺序会选取整行,因此行内的值仍会保持在一起。
运行下面这个固定顺序的示例,可以轻松核对相匹配的特征行和标签:
本节中的代码以及显示的标签或输出仍为英文。
import numpy as np
features = np.array([[10, 100], [20, 200], [30, 300]])
labels = np.array([1, 2, 3])
order = np.array([2, 0, 1])
print(features[order])
print(labels[order])
[[ 30 300]
[ 10 100]
[ 20 200]]
[3 1 2]
这个固定顺序仅用于说明;如果需要随机排列,请使用下文某种打乱方法生成一个顺序。
使用 sklearn.utils.shuffle()
sklearn.utils.shuffle() 接受多个数组,并对它们应用一致的顺序,然后返回打乱后的数组供你赋值。安装 scikit-learn 后,先用 from sklearn.utils import shuffle 导入该函数,再调用 features_shuffled, labels_shuffled = shuffle(features, labels)。将所有相关数组都传入同一次调用,返回结果中的行就会保持配对关系。如果项目已经依赖 scikit-learn,这种方式很方便。不同调用生成的随机顺序可能不同;该函数返回结果供你赋值,不会原地重排源数组。
导入和调用都需要 scikit-learn,而并非所有 Python 环境都安装了它。如果已安装,请先导入函数,再为两个返回数组赋值。这里展示的是依赖特定库的调用语法,并非已执行的示例;下文介绍的 NumPy 方法无需 scikit-learn,可以运行。
使用 NumPy 生成共同排列
numpy.random.permutation(features.shape[0]) 会生成一个打乱后的行索引序列。将它存入 order,然后用 features[order] 和 labels[order] 选取数据。NumPy 高级索引会生成索引结果,源数组仍可按原顺序使用。保留 order,即可复用完全相同的排列、将其应用到更多数组,或与数据一起保存以便后续使用。生成并保留索引顺序,也避免了依赖特定的随机状态接口。
这里生成的同一个顺序用于索引两个数组。打印出的行顺序会变化,但特征与标签仍保持配对:
本节中的代码以及显示的标签或输出仍为英文。
import numpy as np
features = np.array([[10, 100], [20, 200], [30, 300]])
labels = np.array([1, 2, 3])
order = np.random.permutation(features.shape[0])
features_shuffled = features[order]
labels_shuffled = labels[order]
print(features_shuffled)
print(labels_shuffled)
使用 NumPy 打乱共享索引数组
numpy.random.shuffle() 会原地修改传入的序列。用 order = np.arange(features.shape[0]) 创建索引数组,再用 np.random.shuffle(order) 打乱它,最后通过 features[order] 和 labels[order] 选取两个源数组中的数据。这样既能明确表示行顺序,也不会修改源数据。此方法也适用于更多数组:对每个需要保持对齐的数组都使用相同的打乱后索引。只有 order 会被原地打乱;索引得到的结果是独立数组。如果其他代码之后可能修改 order,而你仍需保留此排列,请先复制一份。
这个示例只会修改 order;两个源数组都使用同一组打乱后的索引:
本节中的代码以及显示的标签或输出仍为英文。
import numpy as np
features = np.array([[10, 100], [20, 200], [30, 300]])
labels = np.array([1, 2, 3])
order = np.arange(features.shape[0])
np.random.shuffle(order)
features_shuffled = features[order]
labels_shuffled = labels[order]
print(features_shuffled)
print(labels_shuffled)
检查形状、原地修改和可复现性
数组的第一维必须兼容:它们沿轴 0 的长度必须相同,但其余维度可以不同。例如,特征行矩阵可以与一维标签数组配对。在应用索引顺序之前,先检查各数组的首维长度,确保每个索引对所有数组都有效。
这三种方法对数据的修改方式各不相同。sklearn.utils.shuffle() 返回打乱后的数组供你赋值。numpy.random.permutation() 返回新的索引顺序;用它索引数组会生成重新排序的结果。numpy.random.shuffle() 会修改传入的索引数组;在这些示例中,它不会直接打乱源数组。无论采用哪种方法,都只有在所有相关数组使用相同顺序时,才能保留彼此的对应关系。
若要复现某种排列,请保留生成的索引数组,并再次将它应用于原始数组,或将它与数据一同保存。复用相同的索引顺序即可重现相同排列,无需依赖未指定的随机状态 API。如果需要新的独立排列,请生成新的顺序。这些示例不保证打印出某个特定顺序。