有条件的 Numpy 洗牌

Conditional Numpy shuffling

问题
假设您有一个这样的结构化 np.array

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

并且您想创建一个新的 np.array 大小相同,但打乱了顺序。

例如

second_array = np.random.shuffle(first_array)

second_array 
# np.array([3, 2, 9, 5, 6, 1, 1, 6, 9, 7, 8, 5, 2, 7, 8, 3, 4, 4])
                      

到目前为止,还不错。然而,随机洗牌导致一些重复项彼此非常接近,这是我试图避免的事情。

问题
我如何打乱这个数组,使整数顺序是伪随机的,但每个副本都有很高的概率彼此相距很远?这个问题有更具体的术语吗?

这比 numpy 更像是一个算法问题。一种天真的方法是用最小目标间距 (spacing_condition) 拆分数组,数字应该至少相距那么远。

import numpy as np
first_array = np.array([1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9])
spacing_condition = 3
subarrays = np.split(first_array, spacing_condition)

下一步是从 subarrays 中按顺序选择,这将保证 spacing condition,并从该子数组中删除选择。

但是,对于大型数组,这最后两步的简单循环会很慢。在一个天真的实现之后,种子只是为了复制。

np.random.seed(42)

def choose_over_spacing(subarrays):
    choices = []
    new_subarrays_ = []
    subarray_indices = np.arange(len(subarrays[0]))
    for subarray in subarrays:
        index_to_choose = np.random.choice(subarray_indices, 1)[0]
        number_choice = subarray[index_to_choose]
        choices.append(number_choice)
        new_subarray = np.delete(subarray, index_to_choose)
        new_subarrays_.append(new_subarray)
    return choices, new_subarrays_

all_choices = []
for _ in np.arange(len(subarrays[0])):
    choices, subarrays =  choose_over_spacing(subarrays)
    all_choices = all_choices + choices

检查结果,我们看到我们保证重复的数字至少相隔 3 个数字,因为我们使用 spacing_condition 条件,只要初始拆分有效,就可以选择不同的间距条件。

[2, 6, 8, 3, 6, 7, 2, 5, 9, 3, 4, 9, 1, 4, 8, 1, 5, 7]