从Python中偏向的列表中选择一个随机样本

时间:2018-05-19 19:49:50

标签: python numpy random genetic-algorithm traveling-salesman

为了给出一点背景知识,我正在编写一个遗传算法来解决Traveling Salesman Problem (TSP)。在我的人口中,我有一个从最短到最长(最适合到最不适合)的路径的有序列表,以及它们各自的距离,如下所示:

population = [
[[a, b, c, d], [10.12]],
[[b, c, a, d], [11.33]],
[[d, a, c, b], [11.5]],
[[b, a, d, c], [12.07]]
...]

按照他们的健康状况对人口进行排序后,我需要随机杀死其中一半,但是以这种方式使得成员更健康,他们生存的机会就越大。

  1. 我已尝试使用random.choices()并将概率(偏差)的概率传递到weights参数中,并将我想要的大小原始人口的一半为k,如下所示:

    # returns something like [0.99, 0.75, 0.65, 0.22...]
    bias_weights = [x / len(population) for x in range(len(population))]
    
    random.choices(population, weights=bias_weights, k=len(population) / 2)
    

    上面代码的问题在于,在我的列表中产生重复,并且摆脱它们并将人口规模保持在50%是非常混乱的。

  2. 我还尝试使用numpy库中的np.random.choices(),但它需要我传递的列表为1D ,并且加起来的权重和偏差列表。

  3. 还有其他办法吗?

4 个答案:

答案 0 :(得分:1)

编辑:实际上,我建议只使用以下内容:

while <variable> not in <list>:
    <list>.append(<variable>)

答案 1 :(得分:1)

一次选择一个元素,将其放入一个集合以保证它是唯一的,并继续直到你有足够的元素:

bias_weights = [x / len(population) for x in range(len(population))]

chosen = set()

while size(chosen) < len(population) // 2:
    chosen.add(random.choices(population, weights=bias_weights, k=1))

答案 2 :(得分:1)

我仍然会使用np.random.choice()。通过要求np.random.choice()选择路径的索引而不是路径本身来解决第一个问题。通过缩放权重来解决第二个问题,使它们总和为1。

import numpy as np

a, b, c, d = 1, 2, 3, 4

population = [
[[a, b, c, d], [10.12]],
[[b, c, a, d], [11.33]],
[[d, a, c, b], [11.5]],
[[b, a, d, c], [12.07]]
]

# Build probability array
bias_weights = [x / len(population) for x in range(len(population))]
prob = np.array(bias_weights) / np.sum(bias_weights)

# Get random integers between 0 and len(prob)-1, drawn according to prob
sample_size = 2
choice_indices = np.random.choice(len(prob), size=sample_size, replace=False, p=prob)

# Get corresponding paths
paths = [population[i][0] for i in choice_indices]

答案 3 :(得分:0)

对于没有重复项,您必须使用随机shuffle。算法称为加权随机混洗,并在

中求解

http://nicky.vanforeest.com/probability/weightedRandomShuffling/weighted.html

C ++版本就在这里

C++. Weighted std::shuffle

更新:从第一个链接逐字复制的快速加权随机混洗

from random import random
from bisect import bisect_right
import numpy as np

def weighted_shuffle(a,w):
    r = np.empty_like(a)
    cumWeights = np.cumsum(w)
    for i in range(len(a)):
         rnd = random() * cumWeights[-1]
         j = bisect_right(cumWeights,rnd)
         #j = np.searchsorted(cumWeights, rnd, side='right')
         r[i]=a[j]
         cumWeights[j:] -= w[j]
    return r

a = np.arange(1,1000)
w = np.arange(1,1000)
r = weighted_shuffle(a,w)
print(r[:2])