Python根据离散概率分布采样

一、概率列表+样本列表

        任务描述:我们常常拥有一个概率列表和样本列表,表示每一个样本被选中的概率,并且在概率列表中,概率之和为1。比如,[0.7, 0.2, 0.1]['钢铁侠', '美国队长', '雷神'],两个列表中的元素一一对应;并且,这两个列表共同表示:'钢铁侠'0.7的概率被选中,'美国队长'0.2的概率被选中,'雷神'0.1的概率被选中,我们的目的是想要通过[0.7, 0.2, 0.1]这样的离散概率分布来对['钢铁侠', '美国队长', '雷神']进行采样,并且只采一个样本(当然也可以采多个样本)。

        实际上这样的任务在Python中可以使用相当简单的方式实现,具体请看我的代码。

        代码

import random

# input: probability distribution and correspondence
list_probability = [0.005, 0.015, 0.08, 0.25, 0.3, 0.25, 0.08, 0.015, 0.005]
list_player_role = ['黑寡妇', '蜘蛛侠', '绿巨人', '雷神', '钢铁侠', '奇异博士', '美国队长', '黑豹', '鹰眼']
# sampling
result = random.choices(list_player_role, weights=list_probability, k=1)[0]
# output: sampling one by probability distribution
print(result)

# check the sampling whether is following the probability distribution or not
frequency = [0, 0, 0, 0, 0, 0, 0, 0, 0]
trying_times = 100000
for i in range(trying_times):
    result = random.choices(list_player_role, weights=list_probability, k=1)[0]
    if result == list_player_role[0]:
        frequency[0] += 1
    elif result == list_player_role[1]:
        frequency[1] += 1
    elif result == list_player_role[2]:
        frequency[2] += 1
    elif result == list_player_role[3]:
        frequency[3] += 1
    elif result == list_player_role[4]:
        frequency[4] += 1
    elif result == list_player_role[5]:
        frequency[5] += 1
    elif result == list_player_role[6]:
        frequency[6] += 1
    elif result == list_player_role[7]:
        frequency[7] += 1
    elif result == list_player_role[8]:
        frequency[8] += 1
    else:
        raise Exception('There is something wrong in sampling...')
for i in range(len(frequency)):
    print('角色:%s\t概率: %.3f\t频率: %d/%d=%.4f' % (list_player_role[i], list_probability[i], frequency[i], trying_times, frequency[i]/trying_times))

        输出

钢铁侠
角色:黑寡妇    概率: 0.005    频率: 489/100000=0.0049
角色:蜘蛛侠    概率: 0.015    频率: 1558/100000=0.0156
角色:绿巨人    概率: 0.080    频率: 8011/100000=0.0801
角色:雷神    概率: 0.250    频率: 25094/100000=0.2509
角色:钢铁侠    概率: 0.300    频率: 29957/100000=0.2996
角色:奇异博士    概率: 0.250    频率: 24958/100000=0.2496
角色:美国队长    概率: 0.080    频率: 7867/100000=0.0787
角色:黑豹    概率: 0.015    频率: 1551/100000=0.0155
角色:鹰眼    概率: 0.005    频率: 515/100000=0.0052

        可以看到输出结果中每一个频率都接近于它所对应的概率,这说明采样的过程确实是遵从我们指定的概率分布的。

二、仅有概率列表

        任务描述:不指定样本列表,仅仅有一个概率列表,然后经过采样后输出概率列表中的一个索引。例如,输入[0.7, 0.2, 0.1],输出1,那么1则表示采到了概率0.2。如果输出2,那么表示采到了概率0.1;如果输出0,那么表示采到了概率0.7

        代码

import random

# input: probability distribution and correspondence
list_probability = [0.005, 0.015, 0.08, 0.25, 0.3, 0.25, 0.08, 0.015, 0.005]

# sampling
index = list(range(len(list_probability)))
probability_index = random.choices(index, weights=list_probability, k=1)[0]

# output: sampling one by probability distribution
print(probability_index)

        输出

5

        上述的采样过程仅在Python中的list进行测试,按理来说numpy、pytorch等开源库也是会有相应的实现方法的。经过网上检索,确实有,请移步至sampling from a tensor in torch

三、pytorch实现

        代码

import torch

# input: discrete probability distribution
p = torch.tensor([0.005, 0.015, 0.08, 0.25, 0.3, 0.25, 0.08, 0.015, 0.005])

# sampling: sample one by given probability distribution
index = p.multinomial(num_samples=1, replacement=False)     # replacement=False指不重复采样

# output: the formulation of sampling result
print(index.item())

        输出

4

四、参考

        Choose element(s) from List with different probability in Python

        Sampling from a tensor in Torch

对于离散函数,我们可以使用概率抽样的方法进行采样。具体步骤如下: 1. 首先计算每个离散值对应的概率分布(即归一化后的频率)。 2. 然后生成一个0到1之间的随机数,记为r。 3. 然后对于每个离散值i,计算其累积概率分布,即从第一个离散值到第i个离散值的概率和,记为p_i。 4. 找到第一个满足p_i >= r的离散值i,即为采样结果。 下面是一个简单的Python代码示例: ```python import numpy as np # 定义离散概率分布函数 def discrete_distribution(x): if x == 0: return 0.1 elif x == 1: return 0.3 elif x == 2: return 0.2 elif x == 3: return 0.4 else: return 0 # 进行离散概率分布采样 def discrete_sampling(discrete_distribution, n_samples): samples = np.zeros(n_samples) for i in range(n_samples): # 生成一个0-1之间的随机数 r = np.random.uniform() # 计算累积概率分布 cdf = np.cumsum([discrete_distribution(j) for j in range(5)]) # 找到第一个满足p_i >= r的离散值i for j in range(5): if cdf[j] >= r: samples[i] = j break return samples # 进行离散概率分布采样 samples = discrete_sampling(discrete_distribution, 10000) # 输出采样结果 print("Mean: ", np.mean(samples)) print("Variance: ", np.var(samples)) ``` 在上面的代码中,我们定义了离散概率分布函数 `discrete_distribution` 和离散概率分布采样函数 `discrete_sampling`。我们使用离散概率分布函数进行10000次采样,并输出采样结果的均值和方差。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞机火车巴雷特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值