根据概率从python列表中选择元素

时间:2014-03-28 19:57:26

标签: python

我正在创建一个python脚本,从这里的男性名字列表中随机选择1000个名字:http://www.census.gov/genealogy/www/data/1990surnames/names_files.html

这一切都很好,花花公子,但我希望它能根据人口普查文本文件(第二栏)提供的概率列选择名称。

在过去几个小时里,我一直试图绕过这个问题,但我还没有取得任何实际进展,甚至寻找其他答案。

有人可以帮助我或指出我正确的方向吗?在此先感谢:)

3 个答案:

答案 0 :(得分:5)

加权选择的简单算法是:

  1. 为每个名称指定其相对概率,使得所有概率的总和为1.此相对值称为“重量”。

  2. 选择0到1之间的随机数

  3. 走完清单,在你出发时从你的号码中减去每件物品的重量

  4. 当你转到0或以下时,选择当前项目。

答案 1 :(得分:2)

数据文件的第三个​​列是累计概率,即第二列的运行总和。

选择与累积概率分布相关的随机名称:

  1. 生成0到1之间的随机数,
  2. 找到累积概率大于该值的第一行 随机数。
  3. 选择该行中的名称。

  4. import urllib2
    import random
    import bisect
    
    url = 'http://www.census.gov/genealogy/www/data/1990surnames/dist.male.first'
    response = urllib2.urlopen(url)
    names, cumprobs = [], []
    for line in response:
        name, prob, cumprob, rank = line.split()
        cumprob = float(cumprob)
        names.append(name)
        cumprobs.append(cumprob)
    
    # normalize the cumulative probabilities to the range [0, 1]
    cumprobs = [p/cumprobs[-1] for p in cumprobs]
    # print(cumprobs)
    
    # Generate 1000 names at random, using the cumulative probability distribution
    N = 1000
    selected = [names[bisect.bisect(cumprobs, random.random())] for i in xrange(N)]
    print('\n'.join(selected))
    

    请注意,alias method具有更好的计算复杂性,但仅选择1000个项目,这对您的用例可能不是很重要。

答案 2 :(得分:0)

适用于较小数据集的快速且非常脏黑客只是添加相关名称的次数等于加权分布。请注意,这将占用大量内存,尤其是在较大的数据集中,因此请将此视为仅适用于小加权分布的快速实现。

import random

filename = r"location/of/file"
data = list() # accumulator

with open(filename) as in_:
    for line in in_:
        name, prob, *_ = line.split()
        for _ in range(int(float(prob)*1000)):
            data.append(name)

print(random.choice(data))