【问题标题】:How to retrieve random elements from a Python 3 generator?如何从 Python 3 生成器中检索随机元素?
【发布时间】:2020-12-15 06:33:28
【问题描述】:

有人建议this 生成组合:这会给我组合,但不会像我的问题的结尾中提到的那样具有所需的属性(需要后处理)。 请理解,len(myList) = 10e6 和所需的组合更大。 我正在处理图表。


假设我有一个非常大的列表。我正在使用 itertools 为该列表生成 组合。我想要实现的是随机选择元素,而不使生成器具体化(即使对于 16 GB 的 RAM,它也太大了,我学到了很困难的方法)。

这里是我到目前为止所做的:

import itertools
import random


myList = [('abc',1), ('bcd',2), ('cdef',3), ('adcv',4), ('zofd',5), ('qmkdf',6), ('qmk',7), ('oswd',8)]
# actual list is much larger than above in my case

myCombi_gen = itertools.combinations(myList, r=2)
# Above should generate: [(('abc',1), ('bcd',2)), (('abc',1), ('cdef',3)), .....]

N = 15
counter = 0

for elem in myCombi_gen:
    if random.random() > 0.5:       # selecting based on probability
        print(elem, end=' ')
        counter+=1
        # doing something useful here
        if counter == N:
            break

我的问题是,最终被选中的组合中的元素集中在一个地方。我希望它们更均匀地分布(可能是某种分布?)。一些提醒会有所帮助。


注意事项

即使没有概率选择,我也只需要一小部分组合。如果不使用随机选择,那只会选择前 N 个元素。代码相应更新。

为了清楚起见,对于我的具体情况,我不能执行以下操作:

# Cannot do the following, memory (RAM) usage blows up

all_combi = list(itertools.combinations(myList, r=2))
random.shuffle(all_combi)
selected_combi = random.sample(all_combi, N)


许多人建议的常见方法似乎是,为什么不采样myList 然后生成组合?不,我已经更新了 myList 的结构以便更好地理解。它已排序并且必须保持不变。 itertools.combinations 生成适合我目的的排序组合,这就是我使用它的原因(我对任何其他组合生成器持开放态度)。我希望对组合执行采样,而不是在 myList 的原始元素上执行。

# This approach is unacceptably slow (though I didn't time it):

# making random combinations of size 2
selected = set()
while True:
    left = random.choice(myList)
    right = random.choice(myList)

    if left[1] < right[1] and left[0] != right[0] and (left, right) not in selected and (right, left) not in selected:
        selected.add((left, right))
    if len(selected) == N:
        break

【问题讨论】:

  • 只是一个澄清。您希望获得列表中所有可能的成对组合吗?
  • 更新了问题@TanishqVyas
  • myCombi_gen = itertools.combinations(myList) 似乎不对。 itertools.combinations 需要 2 个参数。
  • 我的错,@AbhigyanJaiswal 我正在写作而不是从我的编辑那里复制,所以错过了r=2 论点。我希望生成大小为 2 的组合,如注释中的示例所示。
  • @anurag 为了获得适当的分布数据,您可以进行所谓的分层抽样。将您的 myList 划分为一些子列表并随机选择这些列表。然后从每个选定的列表中随机选择元素。这样它就不会被本地化到某个部分。

标签: python python-3.x random combinations


【解决方案1】:

使用more_itertools。使用 1M 的排列,只需不到 1 分钟。

random_combination:

返回 iterable 中元素的随机 r 长度子序列。 这相当于从 itertools.combinations(iterable, r).

from more_itertools import random_combination, random_permutation
import string

s = string.ascii_letters
g = {tuple(random_permutation(s)) for i in range(1000000)}

result = set()

while len(result) != 15:
    if (c := random_combination(g, r=2)) not in result: result.add(c)       

【讨论】:

  • 发布了许多答案,有些确实增加了我的知识,但是,发帖者选择删除答案。我的印象是 SO 是为社区服务的。无论如何,我发现这个答案是最简单和优雅的。感谢@Henry,更感谢创作者 (pypi.org/project/more-itertools)。我会接受这一点。 (稍后可能会进行编辑以匹配我的问题。)
【解决方案2】:

这应该有助于解决本地化问题。

import random

N = 15
counter = 0


# List of data
myList = [['abc', 'bcd', 'cdef', 'adcv', 'zofd', 'qmkdf', 'qmk', 'oswd'],
          ['zbc', 'zcd', 'zdef', 'zdcv', 'zofd', 'zmkdf', 'zmk', 'zswd'],
          ['ahhc', 'gcd', 'fdef', 'fdcv', 'gofd', 'gmkdf', 'gmk', 'gswd']]

num_lists = 2

while counter < 15:

    # Randomly select n lists
    sampled_lists_index = random.sample(list(range(len(myList))), num_lists)

    for i in sampled_lists_index:
        # print(i)
        print(random.sample(myList[i], 1)[0], end=" ")

    # Taking care of the formatting
    print("\n")     

    counter += 1

【讨论】:

    【解决方案3】:

    专门针对问题:

    from more_itertools import random_combinations as rc
    
    N = 15
    
    myList = [('abc',1), ('bcd',2), ('cdef',3), ('adcv',4), ('zofd',5), ('qmkdf',6), ('qmk',7), ('oswd',8)]
    
    result = set()
    
    while len(result) != N:
        c = rc(myList, r=2)
        if c not in result:
            result.add(c)
    
    

    这将产生以下内容:

    {(('qmkdf', 6), ('qmk', 7)), (('cdef', 3), ('zofd', 5)), (('adcv', 4), ('zofd', 5)), (('bcd', 2), ('cdef', 3)), (('bcd', 2), ('qmk', 7)), (('adcv', 4), ('qmk', 7)), (('bcd', 2), ('adcv', 4)), (('abc', 1), ('zofd', 5)), (('abc', 1), ('oswd', 8)), (('cdef', 3), ('oswd', 8)), (('adcv', 4), ('qmkdf', 6)), (('cdef', 3), ('qmkdf', 6)), (('bcd', 2), ('oswd', 8)), (('abc', 1), ('qmkdf', 6)), (('bcd', 2), ('qmkdf', 6))}
    

    请注意,组合是随机的,但遵循排序顺序。

    【讨论】:

      猜你喜欢
      • 2023-01-09
      • 2016-07-17
      • 1970-01-01
      • 1970-01-01
      • 2020-12-22
      • 2011-05-25
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多