gpt4 book ai didi

Python - 'x' 列表中具有不同分布的示例

转载 作者:行者123 更新时间:2023-11-30 22:46:36 25 4
gpt4 key购买 nike

在以下代码中,我创建了项目和用户的列表。我将这些项目分为 3 个不同的列表,分别是非常流行、流行和常规项目。

import numpy as np


N_USERS = 20000
N_ITEMS = 1000

items = range(0, N_ITEMS)
users = range(0, N_USERS)

vpop = int(len(items)*0.1)
pop = int(len(items)*0.3)

np.random.shuffle(items)
vpop_items = items[:vpop]
pop_items = items[vpop:pop]
reg_items = items [pop:]

我想从具有不同分布的这些列表中抽取 X 个样本。例如:

list_of_items = sample(vpop_items, pop_items, reg_items, p = [0.5, 0.35, 0.15], X)

其中X是我想要制作的样本数量,P是与列表相对应的分布列表(vpop_itemspop_itemsreg_items)。

所以最终我将在list_of_items中拥有X“items”。

假设X = 100。我总共需要 100 个样本,其中 vpop_items 的概率为 0.5,pop_items 的概率为 0.35,reg_items 的概率为 0.15。抽样必须是无放回的,即任何项目都不能被选择多次。

最佳答案

这是一个简单的 Python 算法,可以满足您的需求。它比您当前所做的更有效率,但我确信有一种更聪明的方法可以做到这一点。 :)

num是想要的样本总数。我们首先生成num 0 - 1 范围内的随机数,并根据所需的累积概率对其进行测试,记录每个概率范围内出现的数字数量。接下来,我们使用第一步中找到的计数作为样本量对每个序列进行采样。最后,我们将这些样本混在一起。

在下面的代码中,我注释掉了进行改组的行,以便更容易地了解测试代码时发生的情况。

from random import seed, random, sample, shuffle
from itertools import accumulate

def multi_sample(seqs, probs, num):
''' Sample from each sequence in list/tuple `seqs` with the corresponding
probability in list/tuple `probs`. Return a list containing `num` samples
'''
# Compute the cumulative probability
# This really should raise ValueError if aprobs[-1] != 1.0
# and we ought to check that len(seqs) == len(probs)...
aprobs = list(accumulate(probs))

# Determine how many samples to take from each seq
counts = [0] * len(seqs)
for _ in range(num):
x = random()
for i, p in enumerate(aprobs):
if x < p:
break
counts[i] += 1

lst = []
for seq, count in zip(seqs, counts):
lst.extend(sample(seq, count))

#shuffle(lst)
return lst

# Test

N_ITEMS = 1000
items = list(range(N_ITEMS))
vpop = int(N_ITEMS * 0.1)
pop = int(N_ITEMS * 0.3)

#shuffle(items)
vpop_items = items[:vpop]
pop_items = items[vpop:pop]
reg_items = items[pop:]

all_items = (vpop_items, pop_items, reg_items)

list_of_items = multi_sample(all_items, probs=[0.5, 0.35, 0.15], num=100)
print(list_of_items)

# Verify

#list_of_items.sort()
#print(list_of_items)

# Should be ~50
print(sum(1 for x in list_of_items if x < vpop))
# Should be ~35
print(sum(1 for x in list_of_items if vpop <= x < pop))

典型输出

[65, 16, 81, 97, 30, 33, 52, 92, 96, 72, 50, 4, 75, 7, 44, 18, 90, 9, 91, 56, 85, 28, 84, 88, 76, 21, 14, 77, 8, 59, 22, 34, 93, 95, 63, 10, 99, 41, 60, 36, 66, 2, 13, 64, 51, 43, 11, 106, 153, 235, 189, 132, 150, 226, 196, 247, 245, 194, 172, 227, 202, 256, 163, 205, 131, 192, 295, 147, 246, 108, 291, 155, 128, 171, 141, 124, 102, 210, 294, 284, 276, 148, 122, 290, 948, 566, 894, 884, 310, 476, 562, 313, 357, 846, 794, 317, 335, 599, 370, 988]
47
37

请注意,此函数可能会失败:如果您调用 sample(seq, count)哪里count > len(seq)它将提高 ValueError: Sample larger than population 。所以你需要确保num足够小,因此不会发生这种情况。为了绝对安全,请确保num <= 小于最小序列的长度。根据给定的数据,num是100,最小的序列是vpop_items ,其中包含 100 项,因此我们无需担心。

感谢 Andras Deak 让我注意到这一重要观点。

<小时/>

正如我之前所说,肯定有一种更聪明的方法来做到这一点:而不是计算 counts在循环中,我们应该能够使用适当的数学直接生成这些计数,但恐怕我不知道(或不记得)如何做到这一点。当然,我们可以“作弊”。 :) 使用给定的数据,我们需要 vpop_items 中的大约 50 个项目, 35 件来自 pop_items其余 15 项来自 reg_items 。所以我们可以设置counts[50, 35, 15]然后对每个计数进行小的随机调整,注意保持总数等于 100。

关于Python - 'x' 列表中具有不同分布的示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40828527/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com