假设我有这样的列表:['a','b','c']
。我需要从这个列表中随机组合,例如['a','c']
。不过,我需要所有组合才具有相同的概率,因此获得['a']
的机会应该与获得['b','c']
的机会完全相同。我真正的名单是22个元素长,因此列举每一个组合是不可能的。我的第一个想法是使用random.sample,然而它需要你指定元素的数量,它必须随机选择,但概率必须是(在这个组合中元素的数量)/(所有组合中元素的数量)是巨大的数字。有没有更好的方法?这将运行数千次,所以有效的解决方案是值得赞赏的。从python中的列表生成一个随机的,等概率的组合
回答
有一个非常有效的方法来做到这一点。给定集合的所有组合的集合被称为power set,给定集合的所有子集合的集合。如果集合S包含m个项目,则总共包含2**m
个可能的组合,包括空集合和S本身。
所以要从S的幂集中随机选择一个组合,我们只需要从range(2**m)
中选择一个随机数n作为幂集的索引,然后生成对应于n的组合。
我们可以通过查看n的二进制展开将索引号n转换为组合。有n个m位。我们将这些比特与S中的项目配对。如果给定位是1,那么为我们的组合选择该项目,如果它是0,我们拒绝该项目。
这是一个简短的演示。
from random import seed, randrange
seed(42)
def indexed_combination(seq, n):
result = []
for u in seq:
if n & 1:
result.append(u)
n >>= 1
if not n:
break
return result
print('Testing indexed_combination')
seq = 'abc'
for i in range(1 << len(seq)):
print(i, ''.join(indexed_combination(seq, i)))
print()
def random_combination(seq):
n = randrange(1 << len(seq))
return indexed_combination(seq, n)
print('Testing random_combination')
seq = 'abcdefghij'
for i in range(20):
print(i, random_combination(seq))
输出
Testing indexed_combination
0
1 a
2 b
3 ab
4 c
5 ac
6 bc
7 abc
Testing random_combination
0 ['c', 'f', 'g', 'h']
1 ['a', 'b', 'e', 'f']
2 ['a', 'b', 'e', 'f', 'j']
3 ['a', 'c', 'e', 'f', 'g', 'h', 'i']
4 ['a', 'd', 'g', 'h', 'i']
5 ['a', 'c', 'd', 'e', 'i']
6 ['a', 'e', 'g', 'h']
7 ['b', 'e', 'f', 'h']
8 ['f', 'g', 'i', 'j']
9 ['a', 'g']
10 ['a', 'c', 'd', 'e', 'f']
11 ['a', 'b', 'c', 'd', 'e', 'f', 'h']
12 ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i']
13 ['c', 'd', 'e', 'g', 'h', 'i']
14 ['b', 'c', 'e', 'f']
15 ['a', 'b', 'c', 'e', 'h', 'i']
16 ['a', 'b', 'd', 'e', 'g', 'i', 'j']
17 ['a', 'b', 'g', 'h', 'i']
18 ['a', 'b', 'c', 'e', 'h', 'i', 'j']
19 ['a', 'd', 'e', 'f', 'j']
我所说的随机函数seed
在脚本的具有固定的种子数开始。在开发使用伪随机数的代码时,我发现这很方便,因为当随机数可重现时,它可以更容易地测试和调试代码。在实际应用中,您应该使用系统熵源对radomizer进行播种。您可以通过取消seed
呼叫或通过执行seed(None)
来轻松完成此操作。如果你想要比标准Mersenee Twister发生器提供的更多的随机性,你可以通过random.SystemRandom
类挂钩到系统的随机源。
我认为这是优越的答案,应该被接受。 [查看关于问题的评论](https://stackoverflow.com/questions/47234958/generate-a-random-equally-probable-combination-from-a-list-in-python#comment81443547_47234958) – piRSquared
我将使用combination
为n创建一个迭代选择i,然后使用chain
来组合所有这样的组合,i等于1到n。组合的总数将为2 ** n - 1
,因此我将从0到2 ** n - 2中随机选取一个整数。最后,使用islice
从迭代中摘取一个整数。
from itertools import islice, combinations, chain
from string import ascii_uppercase
def pickcomb(i):
n = len(i)
allcomb = chain(*(combinations(i, j) for j in range(1, n + 1)))
k = random.randint(0, 2 ** n - 2)
return list(islice(allcomb, k, k + 1))[0]
pickcomb(ascii_uppercase[:22])
('A', 'E', 'F', 'H', 'I', 'K', 'L', 'M', 'O', 'Q', 'S', 'T')
测试一下
我怀疑过大的数字,我们应该看到一个相当均匀分布。我将使用pandas.value_counts
。你可以看到我们有正确数量的观察类型并且分布相当均匀。
import pandas as pd
s = pd.value_counts([pickcomb(ascii_uppercase[:5]) for _ in range(100000)])
print(len(s), 2 ** 5 - 1, s, sep='\n\n')
31
31
(A, B, C, D, E) 3329
(A, D) 3320
(C, D) 3301
(A, D, E) 3277
(D, E) 3276
(B, C, D) 3270
(A, E) 3268
(A, B) 3258
(C, E) 3251
(A, B, C) 3250
(A, B, C, E) 3248
(C, D, E) 3245
(A, C) 3245
(D,) 3241
(C,) 3234
(A, B, D) 3227
(A, C, E) 3220
(B, D, E) 3215
(A, B, E) 3213
(B, C, E) 3213
(B, C, D, E) 3213
(A, C, D) 3211
(B, E) 3194
(B, C) 3193
(A, B, D, E) 3185
(A, B, C, D) 3174
(A, C, D, E) 3158
(E,) 3151
(B,) 3150
(B, D) 3148
(A,) 3122
dtype: int64
- 1. 带概率的随机图生成
- 2. Python numpy根据概率生成随机二进制值数组
- 3. 以概率生成随机数
- 4. Python的numpy的随机数的概率
- 5. 从多个列表中生成随机条目的Python代码
- 6. 生成具有一定概率的随机数
- 7. python:概率的随机样本
- 8. 使用一个概率集合来生成另一个概率集合
- 9. Python的随机列表索引与概率
- 10. 随机的值从枚举的概率
- 11. 随机数字的概率
- 12. 在Python中生成具有已知离散概率的随机数
- 13. 生成一个随机数得到一个随机列表项
- 14. PHP随机概率
- 15. 随机概率PHP
- 16. 概率随机数?
- 17. 如何根据给定的概率生成随机事件?
- 18. 随机生成的概率游戏循环和消除
- 19. 生成给定概率的随机整数
- 20. 用概率分布生成范围内的随机整数
- 21. Matlab中的概率组合
- 22. 如何在python中生成50个随机颜色的列表?
- 23. 以相同的概率选择从多个列表中随机值
- 24. 以概率从列表中选择随机元素
- 25. 通过列表中的值随机生成一组人群
- 26. 如何生成一个不在Python中的列表中的随机ID?
- 27. 概率随机数发生器
- 28. 从python的csv文件中的概率生成数字
- 29. 生成随机列表中的空格
- 30. 从C++中概率分布向量生成随机数发生器
我认为你需要运行两个随机函数,一个用于你将要选择的元素数量(n),另一个用于随机运行n个拾取这些元素。 – Gui
'['a','c']'与'['c','a']'还是不一样? – piRSquared
@piRSquared他说,组合,而不是排列。 –