问题 在numpy数组的每一行中随机调整项目


我有一个像下面这样的numpy数组:

Xtrain = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [1, 7, 3]])

我想分别对每行的项进行随机播放,但不希望每行的shuffle相同(在几个示例中只是随机播放列顺序)。

例如,我想要一个如下输出:

output = np.array([[3, 2, 1],
                   [4, 6, 5],
                   [7, 3, 1]])

如何以有效的方式随机随机地随机移动每一行?我的实际np数组超过100000行和1000列。


9783
2018-05-27 16:35


起源

@Kasramvd根据np文档,多维数组只沿第一轴洗牌: >>> >>> arr = np.arange(9).reshape((3, 3)) >>> np.random.shuffle(arr) >>> arr array([[3, 4, 5], [6, 7, 8], [0, 1, 2]]) - Jack Arnestad
是 suffle() 不接受轴参数。这是一个类似的问题 stackoverflow.com/questions/50415972/... - Kasrâmvd
@Kasramvd如果我理解它,这个问题想要改变行顺序,而不是行中的实际值。 - Jack Arnestad


答案:


由于您只想对列进行随机播放,因此您只需执行该操作即可 洗牌 转换你的矩阵:

In [86]: np.random.shuffle(Xtrain.T)

In [87]: Xtrain
Out[87]: 
array([[2, 3, 1],
       [5, 6, 4],
       [7, 3, 1]])

注意 random.suffle() 在2D数组上混洗行而不是每行中的项目。即改变行的位置。因此,如果你改变转置矩阵行的位置,你实际上是在改组原始数组的列。

如果您仍然想要一个完全独立的shuffle,您可以为每一行创建随机索引,然后使用简单的索引创建最终数组:

In [172]: def crazyshuffle(arr):
     ...:     x, y = arr.shape
     ...:     rows = np.indices((x,y))[0]
     ...:     cols = [np.random.permutation(y) for _ in range(x)]
     ...:     return arr[rows, cols]
     ...: 

演示:

In [173]: crazyshuffle(Xtrain)
Out[173]: 
array([[1, 3, 2],
       [6, 5, 4],
       [7, 3, 1]])

In [174]: crazyshuffle(Xtrain)
Out[174]: 
array([[2, 3, 1],
       [4, 6, 5],
       [1, 3, 7]])

6
2018-05-27 17:08





这种解决方案无论如何都没有效率,但我很乐意考虑它,所以写下来。基本上,您对数组进行了ravel,并创建了一个行标签数组和一个索引数组。您将索引数组洗牌,并使用该数组索引原始和行标签数组。然后你申请一个 稳定 argsort到行标签以将数据收集到行中。应用该索引并重新整形和中提琴,数据由行独立洗牌:

import numpy as np

r, c = 3, 4  # x.shape

x = np.arange(12) + 1  # Already raveled 
inds = np.arange(x.size)
rows = np.repeat(np.arange(r).reshape(-1, 1), c, axis=1).ravel()

np.random.shuffle(inds)
x = x[inds]
rows = rows[inds]

inds = np.argsort(rows, kind='mergesort')
x = x[inds].reshape(r, c)

这是一个 IDEOne链接


3
2018-05-27 17:51





从: https://github.com/numpy/numpy/issues/5173

def disarrange(a, axis=-1):
    """
    Shuffle `a` in-place along the given axis.

    Apply numpy.random.shuffle to the given axis of `a`.
    Each one-dimensional slice is shuffled independently.
    """
    b = a.swapaxes(axis, -1)
    # Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
    # so `a` is shuffled in place, too.
    shp = b.shape[:-1]
    for ndx in np.ndindex(shp):
        np.random.shuffle(b[ndx])
    return

2
2018-05-27 16:55





我们可以创建一个随机的二维矩阵,按行排序,然后使用给定的索引矩阵 argsort 重新排序目标矩阵。

target = np.random.randint(10, size=(5, 5))
# [[7 4 0 2 5]
# [5 6 4 8 7]
# [6 4 7 9 5]
# [8 6 6 2 8]
# [8 1 6 7 3]]

shuffle_helper = np.argsort(np.random.rand(5,5), axis=1)
# [[0 4 3 2 1]
# [4 2 1 3 0]
# [1 2 3 4 0]
# [1 2 4 3 0]
# [1 2 3 0 4]]

target[np.arange(shuffle_helper.shape[0])[:, None], shuffle_helper]
# array([[7, 5, 2, 0, 4],
#       [7, 4, 6, 8, 5],
#       [4, 7, 9, 5, 6],
#       [6, 6, 8, 2, 8],
#       [1, 6, 7, 8, 3]])

说明

  • 我们用 np.random.rand 和 argsort 模仿改组的效果。
  • random.rand 给出随机性。
  • 然后,我们使用 argsort 同 axis=1 帮助排列每一行。这将创建可用于重新排序的索引。

2
2018-05-27 17:15



怎么会比直接排序原始行更好? - Mad Physicist
@MadPhysicist直接对原文进行排序会导致同样的结果,并且不会留下任何随机性。 - Tai
我刚刚得到它。你正在使用这个事实 argsort 有一个轴参数来补偿 shuffle缺乏。聪明 - Mad Physicist
@MadPhysicist确切!感谢您花时间了解这一想法。 - Tai


让我们说你有阵列 a 形状100000 x 1000。

b = np.random.choice(100000 * 1000, (100000, 1000), replace=False)
ind = np.argsort(b, axis=1)
a_shuffled = a[np.arange(100000)[:,np.newaxis], ind]

我不知道这是否比循环更快,因为它需要排序,但有了这个解决方案,你可能会发明更好的东西,例如 np.argpartition 代替 np.argsort


1
2018-05-27 17:15