使用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项的主要内容,如果未能解决你的问题,请参考以下文章