我需要生成一个充满三个"随机"的文件。每行的值(10行),但这些值总和必须等于15.
结构是:" INDEX A B C"。
示例:
1 15 0 0
2 0 15 0
3 0 0 15
4 1 14 0
5 2 13 0
6 3 12 0
7 4 11 0
8 5 10 0
9 6 9 0
10 7 8 0
答案 0 :(得分:4)
如果你想避免需要创建(或遍历)满足排列的完整空间(对于大N
很重要),那么你可以解决这个问题顺序样本。
我的第一种方法是从[0,N]统一绘制一个值,称之为x
。然后从[0,N - x
]统一绘制一个值并将其称为y,然后设置z = N - x - y
。如果你随后洗牌这三个,你会从解决方案的空间中得到一个合理的抽签,但它不会完全统一。
例如,考虑N=3
的位置。然后,(3,0,0)的某些排列的概率是1/4,即使它只是10个可能的三元组中的一个。因此,此权限值包含高最大值
通过对x
y
条件x
可能的值进行比例采样,可以完美地抵消此效果。x
例如,如果N
恰好是y
,则x
只有1个兼容值,但如果Pr(X=x)
为0,则有4个兼容值,即0到3。
换句话说,让(N-x+1)/sum_i(N-i+1)
i
为N
从0到Pr(Y=y | X=x)
。然后让sum(N-i+1 for i in range(0, N+1))
在[0,N-x]上保持一致。
这适用于P(X,Y)= P(Y | X = x)* P(X)= 1 /(N-x + 1)* [N-x + 1] / sum_i(N-对于每个候选三元组,i + 1),被认为是均匀的,1 / sum_i(N-i + 1)。
请注意N
给出了将3个非负整数相加以获得import random
from collections import Counter
def discrete_sample(weights):
u = random.uniform(0, 1)
w_t = 0
for i, w in enumerate(weights):
w_t += w
if u <= w_t:
return i
return len(weights)-1
def get_weights(N):
vals = [(N-i+1.0) for i in range(0, N+1)]
totl = sum(vals)
return [v/totl for v in vals]
def draw_summing_triplet(N):
weights = get_weights(N)
x = discrete_sample(weights)
y = random.randint(0, N-x)
triplet = [x, y, N - x - y]
random.shuffle(triplet)
return tuple(triplet)
的不同方法的数量。我不知道这个的好证据,如果有人在评论中添加一个,我会很高兴!
这是一个以这种方式进行采样的解决方案:
foo = Counter(draw_summing_triplet(3) for i in range(10**6))
print foo
Counter({(1, 2, 0): 100381,
(0, 2, 1): 100250,
(1, 1, 1): 100027,
(2, 1, 0): 100011,
(0, 3, 0): 100002,
(3, 0, 0): 99977,
(2, 0, 1): 99972,
(1, 0, 2): 99854,
(0, 0, 3): 99782,
(0, 1, 2): 99744})
在评论我的原始答案并提供良好反馈的评论中,@ DSM给予了很多赞誉。
在这种情况下,我们可以像这样测试采样器:
{{1}}
答案 1 :(得分:2)
如果数字可以通过任何只使用组合:
from itertools import combinations
with open("rand.txt","w") as f:
combs = [x for x in combinations(range(16),3) if sum(x ) == 15 ][:10]
for a,b,c in combs:
f.write("{} {} {}\n".format(a,b,c))
答案 2 :(得分:0)
这对我来说很简单,并且它使用了随机模块。
import random
def foo(x):
a = random.randint(0,x)
b = random.randint(0,x-a)
c = x - (a +b)
return (a,b,c)
for i in range(100):
print foo(15)