如何从 Python 3 生成器中检索随机元素?

How to retrieve random elements from a Python 3 generator?

有人建议 this 生成组合:这会给我组合,但是不会有 [=36= 中提到的所需属性(需要 post 处理) ]end 我的问题。 请理解,len(myList) = 10e6 并且需要更大的组合。 我正在处理图表。


假设我有一个非常大的列表。我正在使用 itertools 为此列表生成 组合。我想要实现的是随机 select 元素,而不具体化生成器(即使对于 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

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


备注:

即使没有概率 selection,我也只需要一小部分组合。如果不使用随机化的 selection,那将简单地获取第一个 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

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

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

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

random_combination:

Return a random r length subsequence of the elements in iterable. This equivalent to taking a random selection from 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)       

具体问题:

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

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