Python:替代准随机序列

问题描述 投票:-1回答:3

嘿,我有以下问题。我有一个很大的参数空间。就我而言,我有10个维度。但为了简化,假设我有3个变量x1,x2和x3。它们是从1到10的离散数字。现在我创建所有可能的参数组合,并希望将它们用于后处理。在我的实际案例中,组合太多了。所以我想做一个准随机序列搜索来减少搜索空间。但搜索空间中的组合应该尽可能地覆盖它。 (统一分布)。我想在搜索空间中阻止参数组合到Cluster,它应该尽可能地覆盖整个搜索空间。我需要在参数处理中找到参数组合的首选项。有很多方法可以做到这一点,比如Haton,Hammersley或Sobol序列。但他们并不适用于离散数字。一个做准随机序列的包是混乱的。如果我对序列的数量进行舍入,则每个变量的可变数量将在不同的变量组合中出现不止一次。那不是我想要的。我希望每个变量号只出现一次,变量在搜索空间中均匀分布。是否有可能从一开始就创建一个随机的多维变量组合集,其中每个变量只出现一次?例如,在二维网格10x10中,一种可能的组合是对角线。当然在3维中我需要100个组合来覆盖所有参数值,

让我们有一个简单的例子,其中包含1-3个带Sobol序列的三个变量:

import numpy as np
import chaospy as cp

#Create a Joint distributuon of the three varaibles, which ranges going from 1 to 10
distribution2 = cp.J(cp.Uniform(1, 10),cp.Uniform(1, 10),cp.Uniform(1, 10))

#Create 10 numbers in the variable space
samplesSobol = distribution2.sample(10, rule="S")

#Transpose the array to get the variable combinations in subarrays
sobolPointsTranspose = np.transpose(samplesSobol)

示例输出:

[[ 7.89886475  6.34649658  4.8336792 ]
 [ 5.64886475  4.09649658  2.5836792 ]
 [ 1.14886475  8.59649658  7.0836792 ]
 [ 1.21917725  5.01055908  2.5133667 ]
 [ 5.71917725  9.51055908  7.0133667 ]
 [ 7.96917725  2.76055908  9.2633667 ]
 [ 3.46917725  7.26055908  4.7633667 ]
 [ 4.59417725  1.63555908  5.8883667 ]
 [ 9.09417725  6.13555908  1.3883667 ]
 [ 6.84417725  3.88555908  3.6383667 ]]

现在,每个变量编号都是唯一的,但输出不是离散的。我可以围绕它得到:

[[  8.   6.   5.]
 [  6.   4.   3.]
 [  1.   9.   7.]
 [  1.   5.   3.]
 [  6.  10.   7.]
 [  8.   3.   9.]
 [  3.   7.   5.]
 [  5.   2.   6.]
 [  9.   6.   1.]
 [  7.   4.   4.]]

现在的问题是,例如1在第一维中出现两次,在第二维中出现4或在第三维中出现7。

python numpy scipy
3个回答
1
投票

“是否有可能从一开始就创建一个随机的多维变量组合集,其中每个变量只出现一次?”为此,每个变量必须具有相同数量的可能值。在你的例子中,这个数字是10,所以我会用它。

生成随机点的一种方法是堆叠范围的随机排列(10)。像这样,例如,有三个变量:

In [180]: np.column_stack([np.random.permutation(10) for _ in range(3)])
Out[180]: 
array([[6, 6, 4],
       [9, 2, 0],
       [0, 4, 3],
       [5, 9, 5],
       [2, 8, 7],
       [1, 1, 9],
       [8, 3, 8],
       [3, 5, 1],
       [4, 0, 2],
       [7, 7, 6]])

1
投票

这是一个非常晚的答案,所以我认为它不再与原始海报相关,但我试图找到我在下面描述的现有实现时遇到了这个帖子。

听起来你正在寻找类似拉丁超立方体的东西:https://en.wikipedia.org/wiki/Latin_hypercube_sampling。基本上如果我有n个变量并且我想要10个样本,那么每个变量的范围被分成10个区间,每个变量的可能值是(例如)每个区间的中间点。拉丁超立方体算法随机选取样本,使得每个变量的10个值中的每一个仅出现一次。 Warren的答案中的例子是拉丁超立方体的一个例子。

这无助于尽可能地覆盖搜索空间(或者换句话说,检查设计是否填充空间)。莫里斯和米切尔1995年的论文“计算实验的探索性设计”中有一个标准,它通过观察点之间的距离来计算样本的空间填充方式。您可以创建大量不同的拉丁超立方体设计,然后使用该标准选择最佳,或采用初始设计并对其进行操作以提供更好的设计。后者在这里的算法中实现:https://github.com/1313e/e13Tools/blob/master/e13tools/sampling/lhs.py他们在代码中给出了一些例子,例如: 5分和2个变量:

import numpy as np
np.random.seed(0)
lhd(5, 2, method='fixed')

返回类似的东西

array([[ 0.5 ,  0.75],
       [ 0.25,  0.25],
       [ 0.  ,  1.  ],
       [ 0.75,  0.5 ],
       [ 1.  ,  0.  ]])

这将使拉丁超立方体在区间[0,1]上缩放,因此您需要使用例如缩放到参数范围,例如

https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html

这是我运行上面代码时获得的输出之一的示例:enter image description here

根据Morris-Mitchell标准,这个非常适合空间填充。


0
投票

这个答案给出了一个生成4值列表列表的函数,使得[a,b,c,d]是1到10之间的自然数。在每个集合中,参数可能只取任何一个值。

import random

def generate_random_sequences(num_params=4, seed=0)
    random.seed(seed)
    value_lists = [[val for val in range(1, 11)] for _ in range(num_params)]
    for values in value_lists:
        random.shuffle(values)
    ret = [[] for _ in range(num_params)]
    for value_idx in range(10):
        for param_idx in range(num_params):
            ret[param_idx].append(value_lists[param_idx][value_idx])
    return ret

我刚刚看到Warren使用numpy的答案是优越的,你无论如何都使用了numpy。仍然将这个作为纯python实现提交。

© www.soinside.com 2019 - 2024. All rights reserved.