Python指定概率获取随机元素

0x00:

最近写fuzzer遇到了这样的一个需求,生成样本的时候,有些元素需要尽可能的多出现,而有些需要少一点,这就涉及到概率的问题了。然而直接使用random是不行的,暴力的在lib_list上做文章也不行,反而效率更低。看到了python cookbook的两个例子。

0x01:

第一种,给定概率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
#!/usr/bin/python


import random


def random_pick(some_list,probabilities):
x = random.uniform(0,1)
cumulative_probability=0.0
for item,item_probability in zip(some_list,probabilities):
cumulative_probability+=item_probability
if x < cumulative_probability:
break
return item

两个参数,第一个是参数列表,第二个是概率的列表,概率列表里元素相加和必须等于1
比如这么调用:

1
random_pick([1,2,3,4],[0.1,0.2,0.3,0.4])

写代码大概测了下,在大量(>10w)的测试下,比较稳定,按照指定概率产生元素,比如x等于0.1就返回1。
但是不太适合较多参数的情况,需要一个一个指定概率啥的,还要计算好概率和为1…蛋疼。

第二种,给权重
1
2
3
4
5
6
7
8
9
import random
def random_picks(sequence,relative_odds):
  table=[z for x,y in zip(sequence,relative_odds) for z in [x]*y]
  while True:
    yield random.choice(table)

x=random_picks('ciao',[1,1,3,2])
import itertools
print ''.join(itertools.islice(x,8))

第二种根据权重来返回,只要求权重是非负整数,比较容易使用,虽然还是要一个一个给权重,但是总比还要去计算个概率和,好很多。