【问题标题】:Random sampling without replacement when more needs to be sampled than there are samples当需要采样的样本数多于样本数时,无放回随机抽样
【发布时间】:2016-09-15 09:07:18
【问题描述】:

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

  • 设我列表中的元素总数为 N。

  • 我需要从这个列表M个样本中随机抽样而不替换。

  • 如果 M

  • 如果 M > N,则样本必须由 X 乘以列表中的所有 N 个数字组成,其中 X 是 N 整除 M 的次数,即 X = floor(M/N) 然后采样列表中的额外 M-(X*N) 个剩余样本,无需替换。

例如,让我的列表如下:

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

感谢您的帮助!

【问题讨论】:

  • 为什么要结束这个问题?它有什么问题?

标签: python numpy sampling


【解决方案1】:

你可以concatenaterepeatrandom.choice的结果:

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

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

请注意,您可以使用replace parameter 轻松确定choice 是否可以替换使用:

replace : 布尔值,可选 -- 样品是否有更换

【讨论】:

    【解决方案2】:

    我会像这样包装 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]
    

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

    【讨论】:

    • 几乎正是我所需要的,只是无需更换 :) 非常感谢!我也希望它尽可能快:)
    • 没有替代品。注意第二次调用打印结束时的3, 3, 1
    • 给出的所有建议都很好,而且在时间上几乎相等,但我认为你的最终是最快的:)
    • Lnp.array() 时不起作用,因为列表乘法和数组乘法之间存在差异。示例:wrap_choice(np.array(L), 13)。如果这是一项要求,则 OP 最好使用np.repeat() 解决方案之一。
    • @mhawke 据我了解的问题,原始结构和最终结构(带有样本)都是或必须是列表。这里唯一的 np.array()np.random.choice() 产生的
    【解决方案3】:

    对于 0 的情况,这可能是一个解决方案:

    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])
    

    【讨论】:

    • 其实我刚刚意识到它只适用于 M-N
    【解决方案4】:

    使用divmod() 获取列表的重复次数和剩余/不足。然后可以使用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')
    

    【讨论】:

    • 更新为使用 np.repeat() 而不是列表乘法,因为 np.array 的乘法行为不同。这会产生稍微不同的输出,其中重复的项目单独分组在一起,但这似乎符合要求。
    猜你喜欢
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 2019-02-20
    • 2018-05-06
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多