python随机抽号_经典算法:随机抽样

最近发现两个比较有意思的随机抽样算法,分享一下

1. 随机抽样且保持有序

需求:

一家公司购买了他们的第一批电脑,该公司的业务主要是民意调查,现在要开发一个程序:程序的输入是选区名列表以及整数 m,输出是随机选择的 m 个选区名列表。通常选区名有几百个,m 通常在 20 ~ 40。

程序描述:

程序的输入包含两个整数 m 和 n,其中 m

简单点来说,就是有 n 个数, 随机取 m 个,并保持有序。

解法:

我们知道了 n 和 m,轮流判断 n 个数组成的列表中每个数的概率(m/n),每次判断后n=n-1,若当前被判断的数被选择,则m=m-1,否则 m 不变。

假设 5 个数选 2 个,那么意味着每个数的概率都是 2/5 。我们以 2/5 的概率去判断第 1 个数,那么结果有两种,选择1,不选择。当判断第 2 个的时候,在以选择了第 1 个数的情况下,选择 2 的概率是 (2-1)/(5-1)=1/4,在以没选择第 1 个数的情况下,选中 2 的概率是 2/(5-1)=2/4,所以第二个数的概率:(2/5)*(1/4) + (3/5)*(2/4) = 2/5。第二个数的概率和第一个数的概率相等。

证明:

实现:

# Python

import random

# 抽样,从n个中抽m个

def sampling(lists, m, n=None):

selected = []

if n is None:

n = len(lists)

remaining = n-1

for i in range(n):

# random.random()返回 0 ~ 1的随机数

if random.random() * remaining < m:

selected.append(lists[i])

m -= 1

remaining -= 1

return selected

# test

lists = [i for i in range(10)]

print sampling(lists, 3)

# 结果

>>>[4, 5, 7]

2. 在不知道总数的情况下随机选一个

如何从 n 个对象(可以依次看到这 n 个对象,但事先不知道 n 的值)中随机选取一个?例如,如何在事先不知道文本行数的情况下读取该文件,从中随机选择并输出一行?

解法:

我们先设一个变量叫selected,选择第 1 行赋值给 selected,并以 1/2 的概率选择第 2 行并重新赋值给selected, 以 1/3 的概率选择第 3 行并重新赋值给selected。在这以过程结束时, 每一行的选中概率都是相等的(都是 1/n, 其中 n 是文件的总行数)

要证明这个概率可以从最后一行算起,设最后一行的概率为P(n)=1/n, 倒数第二行的概率为P(n-1)=(1-P(n))*(1/(n-1)) = 1/n,倒数第m-1行概率为:

代码:

# Python

import random

def getRandLine(text):

i = 1

selected = ''

for line in text.splitlines():

if (random.random() < (1.0/i)):

selected = line

i += 1

return selected

# test

text = """\

line1

line2

line3

line4

line5

line6

line7

line8

line9

line10

"""

print getRandLine(text)

# 结果

>>>line9

参考: 编程珠玑

文章来源:segmentfault,作者:程淇铭。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:william.shi#ucloud.cn(邮箱中#请改为@)进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

3bd16c71c09c78ecd52251f00b4c6dfa.png

后台-系统设置-扩展变量-手机广告位-内容正文底部

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值