Jos*_*der 214 python random numpy shuffle numpy-ndarray
我有两个不同形状的numpy数组,但长度相同(领先维度).我想改变它们中的每一个,使得相应的元素继续对应 - 即相对于它们的前导索引一致地混洗它们.
此代码有效,并说明了我的目标:
def shuffle_in_unison(a, b):
assert len(a) == len(b)
shuffled_a = numpy.empty(a.shape, dtype=a.dtype)
shuffled_b = numpy.empty(b.shape, dtype=b.dtype)
permutation = numpy.random.permutation(len(a))
for old_index, new_index in enumerate(permutation):
shuffled_a[new_index] = a[old_index]
shuffled_b[new_index] = b[old_index]
return shuffled_a, shuffled_b
Run Code Online (Sandbox Code Playgroud)
例如:
>>> a = numpy.asarray([[1, 1], [2, 2], [3, 3]])
>>> b = numpy.asarray([1, 2, 3])
>>> shuffle_in_unison(a, b)
(array([[2, 2],
[1, 1],
[3, 3]]), array([2, 1, 3]))
Run Code Online (Sandbox Code Playgroud)
然而,这种感觉笨重,效率低,而且速度慢,而且需要使阵列的复制 - 我宁愿他们洗牌在原地的,因为他们将是相当大的.
有没有更好的方法来解决这个问题?更快的执行速度和更低的内存使用率是我的主要目标,但优雅的代码也会很好.
我有另外一个想法是:
def shuffle_in_unison_scary(a, b):
rng_state = numpy.random.get_state()
numpy.random.shuffle(a)
numpy.random.set_state(rng_state)
numpy.random.shuffle(b)
Run Code Online (Sandbox Code Playgroud)
这工作...但它是一个有点吓人,因为我看不出有什么保证它会继续工作 - 它看起来并不像那种有保证跨numpy的版本中生存,例如事情.
mtr*_*trw 314
你可以使用NumPy的数组索引:
def unison_shuffled_copies(a, b):
assert len(a) == len(b)
p = numpy.random.permutation(len(a))
return a[p], b[p]
Run Code Online (Sandbox Code Playgroud)
这将导致创建单独的unison-shuffled数组.
Jam*_*mes 154
X = np.array([[1., 0.], [2., 1.], [0., 0.]])
y = np.array([0, 1, 2])
from sklearn.utils import shuffle
X, y = shuffle(X, y, random_state=0)
Run Code Online (Sandbox Code Playgroud)
要了解更多信息,请访问http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html
Sve*_*ach 66
你的"可怕"解决方案对我来说并不可怕.调用shuffle()两个相同长度的序列导致对随机数生成器的相同调用次数,并且这些是随机数算法中唯一的"随机"元素.通过重置状态,您可以确保对随机数生成器的调用将在第二次调用时给出相同的结果shuffle(),因此整个算法将生成相同的排列.
如果您不喜欢这样,另一种解决方案是将数据存储在一个数组中,而不是从一开始就存储两个数组,并在此单个数组中创建两个视图,模拟您现在拥有的两个数组.您可以使用单个数组进行混洗,并将视图用于所有其他目的.
例如:假设数组a和b看起来像这样:
a = numpy.array([[[ 0., 1., 2.],
[ 3., 4., 5.]],
[[ 6., 7., 8.],
[ 9., 10., 11.]],
[[ 12., 13., 14.],
[ 15., 16., 17.]]])
b = numpy.array([[ 0., 1.],
[ 2., 3.],
[ 4., 5.]])
Run Code Online (Sandbox Code Playgroud)
我们现在可以构造一个包含所有数据的数组:
c = numpy.c_[a.reshape(len(a), -1), b.reshape(len(b), -1)]
# array([[ 0., 1., 2., 3., 4., 5., 0., 1.],
# [ 6., 7., 8., 9., 10., 11., 2., 3.],
# [ 12., 13., 14., 15., 16., 17., 4., 5.]])
Run Code Online (Sandbox Code Playgroud)
现在我们创建模拟原始的视图,a并且b:
a2 = c[:, :a.size//len(a)].reshape(a.shape)
b2 = c[:, a.size//len(a):].reshape(b.shape)
Run Code Online (Sandbox Code Playgroud)
的数据a2和b2与共享c.要同时对两个阵列进行洗牌,请使用numpy.random.shuffle(c).
在生产代码中,您当然会尽量避免创建原始文件a,b并且立即创建c,a2并且b2.
该解决方案能够适应的情况下a,并b有不同的dtypes.
小智 30
很简单的解决方案
randomize = np.arange(len(x))
np.random.shuffle(randomize)
x = x[randomize]
y = y[randomize]
Run Code Online (Sandbox Code Playgroud)
现在,两个数组x,y都以相同的方式随机洗牌
小智 16
詹姆斯在2015年写了一个有用的sklearn 解决方案.但他添加了一个随机状态变量,这是不需要的.在下面的代码中,自动假设来自numpy的随机状态.
X = np.array([[1., 0.], [2., 1.], [0., 0.]])
y = np.array([0, 1, 2])
from sklearn.utils import shuffle
X, y = shuffle(X, y)
Run Code Online (Sandbox Code Playgroud)
ben*_*ers 11
from np.random import permutation
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data #numpy array
y = iris.target #numpy array
# Data is currently unshuffled; we should shuffle
# each X[i] with its corresponding y[i]
perm = permutation(len(X))
X = X[perm]
y = y[perm]
Run Code Online (Sandbox Code Playgroud)
仅使用NumPy就地将任意数量的阵列就地混合在一起.
import numpy as np
def shuffle_arrays(arrays, set_seed=-1):
"""Shuffles arrays in-place, in the same order, along axis=0
Parameters:
-----------
arrays : List of NumPy arrays.
set_seed : Seed value if int >= 0, else seed is random.
"""
assert all(len(arr) == len(arrays[0]) for arr in arrays)
seed = np.random.randint(0, 2**(32 - 1) - 1) if set_seed < 0 else set_seed
for arr in arrays:
rstate = np.random.RandomState(seed)
rstate.shuffle(arr)
Run Code Online (Sandbox Code Playgroud)
并且可以像这样使用
a = np.array([1, 2, 3, 4, 5])
b = np.array([10,20,30,40,50])
c = np.array([[1,10,11], [2,20,22], [3,30,33], [4,40,44], [5,50,55]])
shuffle_arrays([a, b, c])
Run Code Online (Sandbox Code Playgroud)
有几点需要注意:
在shuffle之后,可以np.split使用切片分割数据或使用切片进行分割- 具体取决于应用程序.
你可以做一个像这样的数组:
s = np.arange(0, len(a), 1)
Run Code Online (Sandbox Code Playgroud)
然后洗牌:
np.random.shuffle(s)
Run Code Online (Sandbox Code Playgroud)
现在使用此s作为数组的参数.相同的混洗参数返回相同的混洗向量.
x_data = x_data[s]
x_label = x_label[s]
Run Code Online (Sandbox Code Playgroud)
有一个众所周知的函数可以处理这个问题:
from sklearn.model_selection import train_test_split
X, _, Y, _ = train_test_split(X,Y, test_size=0.0)
Run Code Online (Sandbox Code Playgroud)
只需将 test_size 设置为 0 将避免拆分并为您提供混洗数据。虽然它通常用于拆分训练和测试数据,但它也会对它们进行混洗。
从文档
将数组或矩阵拆分为随机训练和测试子集
包装输入验证和 next(ShuffleSplit().split(X, y)) 和应用程序的快速实用程序,用于将数据输入到单个调用中,以便在单行中拆分(和可选的子采样)数据。
可以对连接列表进行就地改组的一种方法是使用种子(它可以是随机的)并使用 numpy.random.shuffle 进行改组。
# Set seed to a random number if you want the shuffling to be non-deterministic.
def shuffle(a, b, seed):
np.random.seed(seed)
np.random.shuffle(a)
np.random.seed(seed)
np.random.shuffle(b)
Run Code Online (Sandbox Code Playgroud)
就是这样。这将以完全相同的方式对 a 和 b 进行混洗。这也是就地完成的,这总是一个优点。
def shuffle(a, b, seed):
rand_state = np.random.RandomState(seed)
rand_state.shuffle(a)
rand_state.seed(seed)
rand_state.shuffle(b)
Run Code Online (Sandbox Code Playgroud)
调用它时,只需传入任何种子即可提供随机状态:
a = [1,2,3,4]
b = [11, 22, 33, 44]
shuffle(a, b, 12345)
Run Code Online (Sandbox Code Playgroud)
输出:
>>> a
[1, 4, 2, 3]
>>> b
[11, 44, 22, 33]
Run Code Online (Sandbox Code Playgroud)
编辑:修复了重新播种随机状态的代码
这似乎是一个非常简单的解决方案:
import numpy as np
def shuffle_in_unison(a,b):
assert len(a)==len(b)
c = np.arange(len(a))
np.random.shuffle(c)
return a[c],b[c]
a = np.asarray([[1, 1], [2, 2], [3, 3]])
b = np.asarray([11, 22, 33])
shuffle_in_unison(a,b)
Out[94]:
(array([[3, 3],
[2, 2],
[1, 1]]),
array([33, 22, 11]))
Run Code Online (Sandbox Code Playgroud)