Python “如何随机洗牌”;瓷砖“;在numpy数组中
我有一个nxn numpy数组,我想将它均匀地分成nxn块,并随机地洗牌,同时保留块内的图案 例如,如果我有一个大小为(200200)的数组,我希望能够将其划分为16个大小为(50,50)的数组,或者甚至64个大小为(25,25)的数组,并随机洗牌这些数组,同时保留原始数组(200200)的相同形状,并保留较小数组中的数字顺序 我查找了特定的numpy函数,找到了numpy.random.shuffle(x)函数,但这将随机地洗牌数组中的各个元素。我只想在较大的数组中洗牌这些较小的数组 是否有任何numpy功能或快速方法可以做到这一点?我不知道从哪里开始 编辑:为了进一步明确我想要什么: 假设我有一个输入2D数组,其中包含值的形状(10,10):Python “如何随机洗牌”;瓷砖“;在numpy数组中,python,python-3.x,numpy,shuffle,Python,Python 3.x,Numpy,Shuffle,我有一个nxn numpy数组,我想将它均匀地分成nxn块,并随机地洗牌,同时保留块内的图案 例如,如果我有一个大小为(200200)的数组,我希望能够将其划分为16个大小为(50,50)的数组,或者甚至64个大小为(25,25)的数组,并随机洗牌这些数组,同时保留原始数组(200200)的相同形状,并保留较小数组中的数字顺序 我查找了特定的numpy函数,找到了numpy.random.shuffle(x)函数,但这将随机地洗牌数组中的各个元素。我只想在较大的数组中洗牌这些较小的数组 是否有任
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) 我们将使用
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)
随机地相互移动块
块彼此随机w.r.t,同时保持每个块内的顺序与原始数组中的顺序相同
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]])
如果您有权访问
skimage
(它随Spyder提供),您可以使用:
下面的代码可以洗牌行顺序,但保持行项目的原样:
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]])
下面是我使用循环的解决方案
将numpy导入为np
arr=np.arange(36)。重塑(6,6)
def suffle_段(arr、n_段):
断言arr.shape[0]==arr.shape[1],“arr必须是正方形”
断言arr.shape[0]%n\u节==0,“arr大小必须可划分为相等的n\u节”
size=arr.shape[0]//n\u节
新arr=np.空类(arr)
##随机化节的行索引
rand_indxes=np.随机排列(n_段*n_段)
对于范围内的i(n_部分):
##随机化节的列索引
对于范围内的j(n_段):
rand_i=rand_indxes[i*n_sections+j]//n_sections
rand_j=rand_索引[i*n_段+j]%n_段
新阵列[i*尺寸:(i+1)*尺寸,j*尺寸:(j+1)*尺寸]=\
arr[rand_i*大小:(rand_i+1)*大小,rand_j*大小:(rand_j+1)*大小]
返回新地址
结果=覆盖部分(arr,3)
显示(arr)
显示(结果)
数组([[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]])
数组([[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]])
以下是一种尽量避免不必要拷贝的方法:
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
测试脚本(续)
你的意思是说每一行保持完全相同,并且行的顺序不同吗?或者你的意思是一个数字可以跳行,但它应该保持在同一列中?或者,您的意思是,只要生成的行符合某种模式(例如行中的升序),数字就可以跳转列和行?这是三个非常不同的输出,您的描述似乎可以是其中的任何一个。是的,澄清一下,我的意思是数字本身可以跳转行和列,但我希望实际较小的4x4矩阵在这种随机洗牌过程中保持圆滑。我将尝试编辑我的帖子,以使我想要的内容成为一个好主意的示例输出。谢谢,这肯定很接近,但当我将其用于形状(10,10)的数组和大小(5,5)的四个瓷砖时,此函数返回一个形状(4,5,5)的数组,刚刚返回到这个-感谢解决方案。这非常接近,但似乎前三个块(左上角为0、2和4)总是混洗在一起,因此即使该行是随机的,它们也最终位于同一行。但我可以简单地取一个矩阵,用你的函数将它洗牌,转置它,然后再次洗牌,我认为应该可以这样做:result=suffle_部分(suffle_部分(arr,5).T,5)。T@gram_schmidt你抓得很好,我现在已经改正了。在此之前,它是分别洗牌行和列,而不是采取所有可能的排列洗牌。现在,我一次洗牌了所有节的总计数,并在此基础上计算了行和列
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))