如何在numpy数组中随机洗牌

时间:2019-09-20 13:54:39

标签: python python-3.x numpy shuffle

我有一个nxn的numpy数组,我想将其均匀地划分为nxn个图块,并在将图样保留在图块内部的同时,随机将它们洗牌。

例如,如果我有一个大小为(200,200)的数组,我希望能够将其划分为16个大小为(50,50)的数组,甚至64个大小为(25,25)的数组,并且在保留原始数组(200,200)的相同形状并保留较小数组内部的数字顺序的同时,随机地随机排列它们。

我已经查看了特定的numpy函数,并且找到了numpy.random.shuffle(x)函数,但这将随机地对数组的各个元素进行随机排序。我只想在较大的数组中随机排列这些较小的数组。

是否有任何numpy函数或快捷方式可以做到这一点?我不确定从哪里开始。

编辑:进一步明确我想要的内容:

假设我有一个形状为(10,10)的2D输入数组:

0   1   2   3   4   5   6   7   8   9
10  11  12  13  14  15  16  17  18  19
20  21  22  23  24  25  26  27  28  29
30  31  32  33  34  35  36  37  38  39
40  41  42  43  44  45  46  47  48  49
50  51  52  53  54  55  56  57  58  59
60  61  62  63  64  65  66  67  68  69
70  71  72  73  74  75  76  77  78  79
80  81  82  83  84  85  86  87  88  89
90  91  92  93  94  95  96  97  98  99

我选择的图块大小应使其均匀地适合此数组,因此,由于该数组的形状为(10,10),因此我可以选择将其拆分为4(5,5)个图块或25(2, 2)瓷砖。因此,如果我选择4(5,5)个图块,则我想随机地对这些图块进行混洗,以产生一个看起来像这样的输出数组:

50  51  52  53  54  0   1   2   3   4
60  61  62  63  64  10  11  12  13  14
70  71  72  73  74  20  21  22  23  24
80  81  82  83  84  30  31  32  33  34
90  91  92  93  94  40  41  42  43  44
55  56  57  58  59  5   6   7   8   9
65  66  67  68  69  15  16  17  18  19
75  76  77  78  79  25  26  27  28  29
85  86  87  88  89  35  36  37  38  39
95  96  97  98  99  45  46  47  48  49

每个数组(输入数组,输出数组和单独的图块)都将是正方形,以便在随机混洗后,主数组的大小和尺寸保持不变(10,10)。

5 个答案:

答案 0 :(得分:1)

如果您有权使用skimage(Spyder随附),则可以使用view_as_blocks

from skimage.util import view_as_blocks

def shuffle_tiles(arr, m, n):
    a_= view_as_blocks(arr,(m,n)).reshape(-1,m,n)
    # shuffle works along 1st dimension and in-place
    np.random.shuffle(a_)
    return a_

答案 1 :(得分:1)

这是我使用循环的解决方案

import numpy as np

arr = np.arange(36).reshape(6,6)

def suffle_section(arr, n_sections):

    assert arr.shape[0]==arr.shape[1], "arr must be square"
    assert arr.shape[0]%n_sections == 0, "arr size must divideable into equal n_sections"

    size = arr.shape[0]//n_sections


    new_arr = np.empty_like(arr)
    ## randomize section's row index

    rand_indxes = np.random.permutation(n_sections*n_sections)

    for i in range(n_sections):
        ## randomize section's column index
        for j in  range(n_sections):

            rand_i = rand_indxes[i*n_sections + j]//n_sections
            rand_j = rand_indxes[i*n_sections + j]%n_sections

            new_arr[i*size:(i+1)*size, j*size:(j+1)*size] = \
                arr[rand_i*size:(rand_i+1)*size, rand_j*size:(rand_j+1)*size]

    return new_arr


result = suffle_section(arr, 3)


display(arr)
display(result)

array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35]])

array([[ 4,  5, 16, 17, 24, 25],
       [10, 11, 22, 23, 30, 31],
       [14, 15,  2,  3,  0,  1],
       [20, 21,  8,  9,  6,  7],
       [26, 27, 12, 13, 28, 29],
       [32, 33, 18, 19, 34, 35]])

答案 2 :(得分:0)

我们将使用np.random.shuffle和轴排列来获得所需的结果。有两种解释。因此,有两种解决方案。

在每个区块中随机播放

每个块中的元素被随机化,并且在所有块中保持相同的随机顺序。

def randomize_tiles_shuffle_within(a, M, N):
    # M,N are the height and width of the blocks
    m,n = a.shape
    b = a.reshape(m//M,M,n//N,N).swapaxes(1,2).reshape(-1,M*N)
    np.random.shuffle(b.T)
    return b.reshape(m//M,n//N,M,N).swapaxes(1,2).reshape(a.shape)

随机随机播放彼此之间的方块

在保持每个块内的顺序与原始数组相同的同时,各个块相互随机化。

def randomize_tiles_shuffle_blocks(a, M, N):    
    m,n = a.shape
    b = a.reshape(m//M,M,n//N,N).swapaxes(1,2).reshape(-1,M*N)
    np.random.shuffle(b)
    return b.reshape(m//M,n//N,M,N).swapaxes(1,2).reshape(a.shape)

样品运行-

In [47]: a
Out[47]: 
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35]])

In [48]: randomize_tiles_shuffle_within(a, 3, 3)
Out[48]: 
array([[ 1,  7, 13,  4, 10, 16],
       [14,  8, 12, 17, 11, 15],
       [ 0,  6,  2,  3,  9,  5],
       [19, 25, 31, 22, 28, 34],
       [32, 26, 30, 35, 29, 33],
       [18, 24, 20, 21, 27, 23]])

In [49]: randomize_tiles_shuffle_blocks(a, 3, 3)
Out[49]: 
array([[ 3,  4,  5, 18, 19, 20],
       [ 9, 10, 11, 24, 25, 26],
       [15, 16, 17, 30, 31, 32],
       [ 0,  1,  2, 21, 22, 23],
       [ 6,  7,  8, 27, 28, 29],
       [12, 13, 14, 33, 34, 35]])

答案 3 :(得分:0)

这里的代码可以随机排列行顺序,但要完全保留行项目:

import numpy as np 
np.random.seed(0)

#creates a 6x6 array
a = np.random.randint(0,100,(6,6))
a
array([[44, 47, 64, 67, 67,  9],
       [83, 21, 36, 87, 70, 88],
       [88, 12, 58, 65, 39, 87],
       [46, 88, 81, 37, 25, 77],
       [72,  9, 20, 80, 69, 79],
       [47, 64, 82, 99, 88, 49]])

#creates a number for each row index, 0,1,2,3,4,5
order = np.arange(6)

#shuffle index array
np.random.shuffle(order)

#make new array in shuffled order
shuffled = np.array([a[y] for y in order])
shuffled
array([[46, 88, 81, 37, 25, 77],
       [88, 12, 58, 65, 39, 87],
       [83, 21, 36, 87, 70, 88],
       [47, 64, 82, 99, 88, 49],
       [44, 47, 64, 67, 67,  9],
       [72,  9, 20, 80, 69, 79]])

答案 4 :(得分:0)

这是一种努力避免不必要副本的方法:

import numpy as np

def f_pp(a,bs):
    i,j = a.shape
    k,l = bs
    esh = i//k,k,j//l,l
    bc = esh[::2]
    sh1,sh2 = np.unravel_index(np.random.permutation(bc[0]*bc[1]),bc)
    ns1,ns2 = np.unravel_index(np.arange(bc[0]*bc[1]),bc)
    out = np.empty_like(a)
    out.reshape(esh)[ns1,:,ns2] = a.reshape(esh)[sh1,:,sh2]
    return out

时间:

pp 0.41529153706505895
dv 1.3133141631260514
br 1.6034217830747366

测试脚本(续)

# Divakar
def f_dv(a,bs):
    M,N = bs
    m,n = a.shape
    b = a.reshape(m//M,M,n//N,N).swapaxes(1,2).reshape(-1,M*N)
    np.random.shuffle(b)
    return b.reshape(m//M,n//N,M,N).swapaxes(1,2).reshape(a.shape)

from skimage.util import view_as_blocks

# Brenlla shape fixed by pp
def f_br(arr,bs):
    m,n = bs
    a_= view_as_blocks(arr,(m,n))
    sh = a_.shape
    a_ = a_.reshape(-1,m,n)
    # shuffle works along 1st dimension and in-place
    np.random.shuffle(a_)
    return a_.reshape(sh).swapaxes(1,2).reshape(arr.shape)

ex = np.arange(100000).reshape(1000,100)
bs = 10,10
tst = np.tile(np.arange(np.prod(bs)).reshape(bs),np.floor_divide(ex.shape,bs))

from timeit import timeit
for n,f in list(globals().items()):
    if n.startswith('f_'):
        assert (tst==f(tst,bs)).all()
        print(n[2:],timeit(lambda:f(ex,bs),number=1000))