2014-03-28 113 views
6

我創建一個Python腳本,隨機設在這裏的男性名字的列表中選取1000名:http://www.census.gov/genealogy/www/data/1990surnames/names_files.html蟒蛇從列表中選擇元素基於概率

該工程的所有罰款和花花公子,但我想它以便根據人口普查文本文件提供的概率列(第二列)選擇名稱。

我一直試圖在過去的幾個小時裏圍繞這一點,但是我還沒有取得任何真正的進展,甚至尋找其他答案。

任何人都可以幫助我或指出我在正確的方向嗎?感謝提前:)

+1

這可能是有益的 - http://stackoverflow.com/questions/352670/weighted-random-selection-with-and-without-replacement –

+1

禮Bendersky對頁面[加權隨機選擇(HTTP:/ Python中的/eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/)非常豐富。 – DSM

+0

@DSM該頁面極其有用。謝謝! – flexcalibur6

回答

5

一個簡單的算法權重選擇是:

  1. 爲每一個名字的相對概率,使得所有的概率之和爲1。這種相對值被稱爲「權重」。

  2. 選擇一個隨機數0和1之間

  3. 走在列表中,你的電話號碼從其減去每個項目的權重,當您去

  4. 當你去到0以下,挑電流項目。

+0

這可以工作,但問題是(可能),我從1200個名字中選擇1000次。那麼這種方法需要很長時間嗎? – flexcalibur6

+0

你不能比這更快:它運行在線性時間,幾乎是最小的恆定因子。很明顯,在隨機選擇之前,權重只計算一次 – slezica

2

數據文件的第三是累積概率,所述第二塔的運行總和。

要針對選擇一個隨機名稱的累積概率分佈:

  1. 生成0和1之間的隨機數,
  2. 在第一行的累積概率比 隨機數大。
  3. 在該行中選擇名稱。

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個項目的選擇,這可能不是你的使用情況非常重要。

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))