使用python从列表中随机提取x项

Posted

技术标签:

【中文标题】使用python从列表中随机提取x项【英文标题】:Randomly extract x items from a list using python 【发布时间】:2014-06-20 23:22:32 【问题描述】:

从两个列表开始,例如:

lstOne = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
lstTwo = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

我想让用户输入他们想要提取的项目数量,作为整个列表长度的百分比,以及从每个列表中随机提取的相同索引。例如说我想要 50% 的输出是

newLstOne = ['8', '1', '3', '7', '5']
newLstTwo = ['8', '1', '3', '7', '5']

我使用以下代码实现了这一点:

from random import randrange

lstOne = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
lstTwo = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

LengthOfList = len(lstOne)
print LengthOfList

PercentageToUse = input("What Percentage Of Reads Do you want to extract? ")
RangeOfListIndices = []

HowManyIndicesToMake = (float(PercentageToUse)/100)*float(LengthOfList)
print HowManyIndicesToMake

for x in lstOne:
    if len(RangeOfListIndices)==int(HowManyIndicesToMake):
        break
    else:
        random_index = randrange(0,LengthOfList)
        RangeOfListIndices.append(random_index)

print RangeOfListIndices


newlstOne = []
newlstTwo = []

for x in RangeOfListIndices:
    newlstOne.append(lstOne[int(x)])
for x in RangeOfListIndices:
    newlstTwo.append(lstTwo[int(x)])

print newlstOne
print newlstTwo

但我想知道是否有更有效的方法来执行此操作,在我的实际用例中,这是从 145,000 个项目中进行二次抽样。此外, randrange 在这个尺度上是否充分没有偏差?

谢谢

【问题讨论】:

@devnull 您过于激进地将问题标记为可能的重复问题。另一个问题是“我如何制作随机样本”。这个问题提出了两个更有趣的问题,“我如何从多个列表中制作相同的样本”和“内置随机函数是否有偏差”。 @RaymondHettinger 白天早些时候观看了您的一个 Python 视频,我怎么能反驳呢? (关闭投票被撤回。) 【参考方案1】:

问。 I want to have the user input how many items they want to extract, as a percentage of the overall list length, and the same indices from each list to be randomly extracted.

A. 最直接的方法直接符合您的规范:

 percentage = float(raw_input('What percentage? '))
 k = len(data) * percentage // 100
 indicies = random.sample(xrange(len(data)), k)
 new_list1 = [list1[i] for i in indicies]
 new_list2 = [list2[i] for i in indicies]

问。 in my actual use case this is subsampling from 145,000 items. Furthermore, is randrange sufficiently free of bias at this scale?

A. 在 Python 2 和 Python 3 中,random.randrange() 函数完全消除了偏差(它使用内部的 _randbelow() 进行多个随机选择直到找到无偏差结果的方法。

在 Python 2 中,random.sample() 函数略有偏差,但仅在 53 位的最后一个舍入中。在 Python 3 中,random.sample() 函数使用内部 _randbelow() 方法并且没有偏差。

【讨论】:

感谢您的详尽回答。我在这段代码中遇到的一个问题是您不能输入诸如 12.5% 之类的值并让代码四舍五入到最接近的值。您将如何在示例中实现这一点? 只是为了澄清,我不是指四舍五入的百分比值:我的意思是如果你有 1300 个项目并且你想要其中的 12.5%,那么代码将返回 163 个项目(12.5% 是 162.5 个项目)而不是 169 个项目(如果将百分比四舍五入到 13%) @PaulBarr 不用担心。我只是将 int 转换为 float 转换。 还有一个问题,因为索引是一个浮点数而不是整数,所以我只是添加了 k = round(k) 和 k = int(k) 来四舍五入。感谢您的帮助!【参考方案2】:

只需将zip 你的两个列表放在一起,使用random.sample 进行采样,然后再次使用zip 转换回两个列表。

import random

_zips = random.sample(zip(lstOne,lstTwo), 5)

new_list_1, new_list_2 = zip(*_zips)

演示:

list_1 = range(1,11)
list_2 = list('abcdefghij')

_zips = random.sample(zip(list_1, list_2), 5)

new_list_1, new_list_2 = zip(*_zips)

new_list_1
Out[33]: (3, 1, 9, 8, 10)

new_list_2
Out[34]: ('c', 'a', 'i', 'h', 'j')

【讨论】:

这是一个很好的方法,但我不能赞成它,因为它做了太多的工作(循环整个人口并为每对保存一个元组)。最好建立一个独特的索引的小列表并提取所需的选择。 这里没有分歧:-)【参考方案3】:

在我看来,你的做法基本没问题。

如果您想避免多次对同一对象进行采样,您可以按照以下步骤进行:

a = len(lstOne)
choose_from = range(a)          #<--- creates a list of ints of size len(lstOne)
random.shuffle(choose_from)
for i in choose_from[:a]:       # selects the desired number of items from both original list
    newlstOne.append(lstOne[i]) # at the same random locations & appends to two newlists in
    newlstTwo.append(lstTwo[i]) # sequence

【讨论】:

这对于大量人口来说工作量太大了。 random.sample() 函数使用的内存更少,对随机数生成器的调用也更少。 谢谢您,先生,您当然是正确的。我不知道 random.sample;每次你发帖我都会学到一些东西。

以上是关于使用python从列表中随机提取x项的主要内容,如果未能解决你的问题,请参考以下文章

Python - 如何从列表中提取最后一个 x 元素

使用python从不同长度的元组列表中删除重复项

从python中的类列表中随机选择x个项目

如何在 Swift 中从数组中提取随机项?

使用php从mysql中提取名称的随机顺序

Scrapy/Python/XPath - 如何从数据中提取数据?