【问题标题】:generate random weigted string file in python在python中生成随机加权字符串文件
【发布时间】:2016-12-21 07:42:21
【问题描述】:

我正在尝试从长度为 3900 的 ['A','B','C','D','E'] 字符生成字符串,并且每个字符的概率应为: {'A':0.1, 'B':0.3, 'C':0.3, 'D':0.1, 'E':0.2 } 在这个字符串中 我写了以下代码:

from random import random
from bisect import bisect

def weighted_choice(choices):
    values, weights = zip(*choices)
    total = 0
    cum_weights = []
    for w in weights:
        total += w
        cum_weights.append(total)
    x = random() * total
    i = bisect(cum_weights, x)
    return values[i]
string_ = ''
for i in range(0,3900):
    string_ = string_ + weighted_choice([("A",10), ("B",30), ("C",30),("D",10),("E",20)])

with open("rand_file","w") as f:
        f.write(string_)

但它不会根据概率生成字符串(文件)。它以这样的概率生成:

C 0.2500264583 
B 0.2499284457 
E 0.1666428313 
D 0.0833782424 
A 0.0833758065 

概率导致for循环每次都单独运行,没有考虑之前的结果。

请帮忙解决这个问题?

【问题讨论】:

    标签: python python-2.7 python-3.x random


    【解决方案1】:

    如果您只是使用列表['A','B','B','B','C','C','C','D','E','E'] 并从中随机选择一个项目,您可以完全摆脱代码中所有加权的东西,并且加权将被内置。

    您可以在下面的示例中看到这一点(是的,我不怀疑它可以写得更好,但它只是一个概念验证,而不是生产就绪的纯白雪代码):

    from random import random, seed
    
    def choice(lst):
        return lst[int(random() * len(lst))];
    
    seed()
    
    (a, b, c, d, e, t) = (0, 0, 0, 0, 0, 0)
    
    for i in range(1000):
        x = choice('ABBBCCCDEE')
        if (x == 'A'): a += 1
        if (x == 'B'): b += 1
        if (x == 'C'): c += 1
        if (x == 'D'): d += 1
        if (x == 'E'): e += 1
        t += 1
    
    print ("a =", a, "which is", a * 100 / t, "%")
    print ("b =", b, "which is", b * 100 / t, "%")
    print ("c =", c, "which is", c * 100 / t, "%")
    print ("d =", d, "which is", d * 100 / t, "%")
    print ("e =", e, "which is", e * 100 / t, "%")
    

    输出匹配(大致)所需的分布:

    a = 101 which is 10.1 %
    b = 297 which is 29.7 %
    c = 299 which is 29.9 %
    d = 102 which is 10.2 %
    e = 201 which is 20.1 %
    

    现在,如果您的分布是 99.9% A 和 0.1% B(这将是一个相当长的字符串传递给 choice),这显然会很烦人,但这应该足以满足您的分布.

    【讨论】:

    • 这在大多数情况下可能已经足够了。虽然不是A:0.50000000001, B:0.49999999999的最坏情况@
    【解决方案2】:

    您可以根据权重生成所有字母,然后将它们随机洗牌,最后加入它们。比如:

    from random import shuffle
    N = 3900 # the string length
    doc = {'A':0.1, 'B':0.3, 'C':0.3, 'D':0.1, 'E':0.2 } #weights
    letters = []
    for key in doc.keys():
        m = int(doc[key] * N) #generate correct number of letter
        letters.append(list(key * m))
    
    letters = [item for sublist in letters for item in sublist] # flatten the list
    shuffle(letters) # shuffle all letters randomly
    result = ''.join(letters) # join all letter to make one string
    
    print(len(result))
    # 3900
    

    【讨论】:

    • m = int(doc[key] * N) 不能保证最后是 len(letters) == N,因为 int() 总是会向下舍入。
    • منونم مهدی :D.
    【解决方案3】:

    这实际上与paxdiablo的解决方案相同,只是更通用一点(对于您的简单示例,他的解决方案更好。+1):

    import random
    
    choice = [("A",10), ("B",30), ("C",30),("D",10),("E",20)]
    choose_from = ''.join(x * letter for letter, x in choice)
    
    print(choose_from)
    #  AAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDetc...
    
    print(random.choice(choose_from))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      相关资源
      最近更新 更多