2017-04-03 275 views
2

本质上,我试图做的是从列表中随机选择项目,同时保持内部分布。看下面的例子。我如何从Python中的列表中随机抽样,同时保持数据分布

a = 17% 
b = 12% 
c = 4% 
etc. 

“a”在列表中有1700个项目。 “b”在列表中有1200个项目。 “c”在列表中有400个项目。

而不是使用的所有信息,我想模仿A,B,C的分布,样本等

因此我们的目标是直到结束,从

170随机选择项目“一”从“b”从 40个随机选择的项目“C”

我知道如何随机选择从列表中的信息,但我一直无法弄清楚如何随机选择 120随机选择项目同时迫使结果具有相同的分布。

+0

你不能强迫样本类似人口,它是随机的。 –

+0

你能澄清一下吗?你有三个列表,或者你想将一个样本随机分成三个列表? – roganjosh

+1

例如['numpy.random.choice'](https://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.random.choice.html)允许您传递概率参数(a可能性列表),但我很难理解你想要做什么,所以我不知道它是否合适。 – roganjosh

回答

2

如果你的清单不是很庞大,如果内存不是问题,你可以使用这个简单的方法。

要获得n元素从abc,你可以在三个列表拼接在一起,并选择从结果列表中随机元素与random.choice

import random 

n = 50 
a = ['a'] * 170 
b = ['b'] * 120 
c = ['c'] * 40 
big_list = a + b + c 
random_elements = [random.choice(big_list) for i in range(n)] 
# ['a', 'c', 'a', 'a', 'a', 'b', 'a', 'c', 'b', 'a', 'c', 'a', 
# 'a', 'a', 'a', 'b', 'b', 'a', 'a', 'a', 'a', 'a', 'c', 'a', 
# 'c', 'a', 'b', 'a', 'a', 'c', 'a', 'b', 'a', 'c', 'b', 'a', 
# 'a', 'b', 'a', 'b', 'a', 'a', 'c', 'a', 'c', 'a', 'b', 'c', 
# 'b', 'b'] 

对于每一个元素,你会得到一个len(a)/len(a + b + c)a获得元素的概率。

尽管您可能会多次获得相同的元素。如果你不希望发生这种情况,你可以使用random.shuffle

+1

这很简单,在这里可能就够了。但是,如果表现在某种程度上重要,这种幼稚的方法并不会引人注目。在实践中,这种时间内存折衷方式对于缓存行为来说可能是不好的(并且使用的内存比需要的多得多;冗余很多)。 – sascha

0

从我的理解,你有三个不同的人口,你想从这些人口中随机抽样,但挑选某些人群的倾向可能性。在这种情况下,首先随机产生对应于每个群体的指数的列表(如我将它们组合成称为combined的单个二维数组),更容易。

然后,您可以遍历随机生成的索引列表,这会给出您将要选择的人群,然后使用np.random.choice()从该数据中随机选择。

import numpy as np 

sample_a = np.arange(1, 1000) 
sample_b = np.arange(1001, 2000) 
sample_c = np.arange(2001, 3000) 

combined = np.vstack((sample_a, sample_b, sample_c)) 

distributions = [0.7, 0.2, 0.1] # The skewed probability distribution for sampling 

sample = np.random.choice([0, 1, 2], size=10, p=distributions) # Choose indices with skewed probability 

combined_pool = [] 

for arr in sample: 
    combined_pool.append(np.random.choice(combined[arr])) 
0

在选择中“模仿”这种分布的一种方法是简单地将列表合并为一个,然后从该列表中选择所需的总项数。如果需要选择的项目总数很大,那么这个近似值就会很好。

请注意,它不能保证从每个列表中确切地选择这些数量。但是,如果列表很大,并且此例程运行很多,则平均值应该很高。

import random 
total = a + b + c + ... 
samples = [] 
number = len(total)/10 
for i in range(number): 
    samples.append(total[random.rand(0, len(total) - 1]) 
+1

与我已发布的答案相比,附加值是多少? –

-1

只需在列表中使用shuffle,并取第n个元素。

+0

在哪个列表? OP至少有3个。注意:我没有downvote。 'shuffle'是一个有趣的想法,因为它可以避免重复元素。 –

0

手动操作非常简单。让我们存储在(value, probability)对象的列表数据:

data = [(a, 0.17), (b, 0.12), (c, 0.04), ...] 

这是将帮助您选择遵循的概率分布的随机值的函数:

import random 
def select_random_element(data): 
    sample_proba = random.uniform(0, 1) 
    total_proba = 0 
    for (value, proba) in data: 
     total_proba += proba 
     if total_proba >= sample_proba: 
      return value 

最后,这就是我们选择N随机物品:

random_items = [select_random_element(data) for _ in range(0, N)] 

这不需要任何额外的内存。但是,时间复杂度为O(len(data)*N)。这可以通过对数据进行排序名单通过预先降低概率加以改进:

data = sorted(data, key=lambda i: i[1], reverse=True) 

注意,我认为你的数据的总概率为1。如果没有,你应该在上面的代码写random.uniform(0, total_probability)代替random.uniform(0, 1),与:

total_probability = sum([i[1] for i in data])