当需要抽样的数量多于样本数量时,不放回地随机抽样

Random sampling without replacement when more needs to be sampled than there are samples

我需要从数字列表中生成样本,在这种情况下,我可能需要采样比我拥有的更多的数字。更明确地说,这是我需要做的:

例如,让我的列表如下:

L = [1, 2, 3, 4, 5]

我需要采样 8 个样本。然后首先,我对完整列表进行一次采样,然后随机添加 3 个元素而不进行替换,例如我的样本可能是:

Sampled_list = [1, 2, 3, 4, 5, 3, 5, 1]

如何在 Python 的计算时间方面尽可能高效地实现这样的代码?这可以在没有 for 循环的情况下完成吗?

目前我正在使用 for 循环实现它,但这对我的目的来说效率太低了。我也尝试过 Numpy 的 random.choice 没有替换,但我需要 M <= N。

感谢您的帮助!

我会像这样包装 numpy 的 random.choice()

L = [1, 2, 3, 4, 5]

def wrap_choice(list_to_sample, no_samples):
    list_size = len(list_to_sample)
    takes = no_samples // list_size
    samples = list_to_sample * (no_samples // list_size) + list(np.random.choice(list_to_sample, no_samples - takes * list_size))
    return samples

print(wrap_choice(L, 2))   # [5, 1]
print(wrap_choice(L, 13))  # [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 3, 3, 1]

编辑:不需要检查长度。当请求超过列表的长度时,您使用的算法也适用于这种情况。

你可以concatenate the results of repeat and random.choice:

np.concatenate((np.repeat(L, M // len(L)), np.random.choice(L, M - M // len(L))))

首先,根据需要重复序列,然后选择所需的剩余数量;最后,将两个数组连接起来。

请注意,您可以使用 replace parameter:

轻松确定 choice 是否可以替换或不替换

replace : boolean, optional -- Whether the sample is with or without replacement

下面是情况下 0 < M-N < max(L) 的可能解决方案:

import numpy as np
from numpy.random import random

l = np.array([1, 2, 3, 4, 5])
rand = [ i for i in l[np.argsort(np.amax(l))[:M-N]] ]

new_l = np.concatenate(l,rand)

这是一个例子:

l = np.array([1,2,3,4,5])
M, N = 7, len(l)
rand = [i for i in l[np.argsort(np.random(np.amax(l)))][:M-N]]
new_l = np.concatenate(l,rand)

这是输出:

new_list = np.array([1,2,3,4,5,3,4])

使用divmod()获取列表的重复次数和remainder/shortfall。然后可以使用 numpy.random.choice().

从列表中随机选择不足部分
import numpy as np

def get_sample(l, n):
    samples, shortfall = divmod(n, len(l))
    return np.concatenate((np.repeat(l, samples), np.random.choice(l, shortfall, False)))


>>> get_sample(range(100), 10)
array([91, 95, 73, 96, 18, 37, 32, 97,  4, 41])
>>> get_sample(range(10), 100)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
   2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
   4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
   6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
   9, 9, 9, 9, 9, 9, 9, 9])
>>> get_sample([1,2,3,4], 0)
array([], dtype=int64)
>>> get_sample([1,2,3,4], 4)
array([1, 2, 3, 4])
>>> get_sample([1,2,3,4], 6)
array([1, 2, 3, 4, 4, 3])
>>> get_sample([1,2,3,4], 6)
array([1, 2, 3, 4, 3, 2])

>>> get_sample(list('test string'), 6)
array(['n', 's', 'g', 's', 't', ' '], 
  dtype='|S1')
>>> get_sample(np.array(list('test string')), 4)
array(['r', 't', 's', 'g'], 
  dtype='|S1')