Python 内置模块之 random

常用API 

import random


# 随机小数
print(random.random())      # 大于0且小于1之间的小数。0<= n<1.0
print(random.uniform(1,3))  # 大于1小于3的小数


# 随机整数
print(random.randint(1,5))      # 大于等于1且小于等于5之间的整数


#从指定范围内,按指定基数递增的集合中 获取一个随机数。
random.randrange([start], stop[, step])
random.randrange(10, 30, 2)   # 结果相当于从[10, 12, ... 26, 28]序列中获取一个随机数。
random.randrange(10, 30, 2)   # 在结果上与 random.choice(range(10, 30, 2) 等效。


# 随机选择一个返回
print(random.choice([1,'23',[4,5]]))     # 1或者23或者[4,5]
# 随机选择多个返回,返回的个数为函数的第二个参数
print(random.sample([1,'23',[4,5]],2))   # 列表元素任意2个组合[[4, 5], '23']


# 打乱列表顺序
item=[1,3,5,7,9]
random.shuffle(item) # 打乱次序
print(item)         # [5, 1, 3, 7, 9]
random.shuffle(item)
print(item)         # [5, 9, 7, 1, 3]

加权随机算法实现

方法一

最简单的方法可以这样:把序列按权重值扩展成:lists=[A,A,A,A,A,B,B,C,C,D],然后random.choice(lists)随机选一个就行。虽然这样选取的时间复杂度是O(1),但是数据量一大,空间消耗就太大了。

# coding:utf-8
import random


def weight_choice(list, weight):
    """
    :param list: 待选取序列
    :param weight: list对应的权重序列
    :return:选取的值
    """
    new_list = []
    for i, val in enumerate(list):
        new_list.extend(val * weight[i])
    return random.choice(new_list)


if __name__ == "__main__":
    print(weight_choice(['A', 'B', 'C', 'D'], [5, 2, 2, 1]))

 

 

方法二

比较常用的方法是这样:计算权重总和sum,然后在1到sum之间随机选择一个数R,之后遍历整个集合,统计遍历的项的权重之和,如果大于等于R,就停止遍历,选择遇到的项。

还是以上面的集合为例,sum等于10,如果随机到1-5,则会在遍历第一个数字的时候就退出遍历。符合所选取的概率。

选取的时候要遍历集合,它的时间复杂度是O(n)。

 

# coding:utf-8
import random

list = ['A', 'B', 'C', 'D']


def weight_choice(weight):
    """
    :param weight: list对应的权重序列
    :return:选取的值在原列表里的索引
    """
    t = random.randint(0, sum(weight) - 1)
    for i, val in enumerate(weight):
        t -= val
        if t < 0:
            return i


if __name__ == "__main__":
    print(list[weight_choice([5, 2, 2, 1])])

方法三

可以先对原始序列按照权重排序。这样遍历的时候,概率高的项可以很快遇到,减少遍历的项。(因为rnd递减的速度最快(先减去最大的数))比较{A:5,B:2,C:2,D:1}和{B:2,C:2,A:5,D:1}前者遍历步数的期望是5/10*1+2/10*2+2/10*3+1/10*4=19/10而后者是2/10*1+2/10*2+5/10*3+1/10*4=25/10。这样提高了平均选取速度,但是原序列排序也需要时间。先搞一个权重值的前缀和序列,然后在生成一个随机数t后,可以用二分法来从这个前缀和序列里找,那么选取的时间复杂度就是O(logn)了。

# coding:utf-8
import random
import bisect

list = ['A', 'B', 'C', 'D']


def weight_choice(weight):
    """
    :param weight: list对应的权重序列
    :return:选取的值在原列表里的索引
    """
    weight_sum = []
    sum = 0
    for a in weight:
        sum += a
        weight_sum.append(sum)
    t = random.randint(0, sum - 1)
    return bisect.bisect_right(weight_sum, t)


if __name__ == "__main__":
    print(list[weight_choice([5, 2, 2, 1])])

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值