Для четырех букв, вот что-то быстро с моей головы:
from random import random
def randABCD(n, pA, pB, pC, pD):
# assumes pA + pB + pC + pD == 1
cA = pA
cB = cA + pB
cC = cB + pC
def choose():
r = random()
if r < cA:
return 'A'
elif r < cB:
return 'B'
elif r < cC:
return 'C'
else:
return 'D'
return ''.join([choose() for i in xrange(n)])
У меня нет сомнений, что это можно сделать намного чище / короче, сейчас я немного тороплюсь.
Причина, по которой я не был бы доволен Дэвидом в ответе Дакоты об использовании списка повторяющихся символов, заключается в том, что в зависимости от ваших вероятностей, возможно, не удастся создать список с дубликатами в нужных числах для имитации вероятностей, которые вы хочу. (Ну, я думаю, это всегда возможно, но вам может понадобиться огромный список - что, если ваши вероятности были 0,11235442079, 0,4072777384, 0,2297927874, 0,25057505341?)
РЕДАКТИРОВАТЬ : вот более понятная универсальная версия, которая работает с любым количеством букв с любыми весами:
from bisect import bisect
from random import uniform
def rand_string(n, content):
''' Creates a string of letters (or substrings) chosen independently
with specified probabilities. content is a dictionary mapping
a substring to its "weight" which is proportional to its probability,
and n is the desired number of elements in the string.
This does not assume the sum of the weights is 1.'''
l, cdf = zip(*[(l, w) for l, w in content.iteritems()])
cdf = list(cdf)
for i in xrange(1, len(cdf)):
cdf[i] += cdf[i - 1]
return ''.join([l[bisect(cdf, uniform(0, cdf[-1]))] for i in xrange(n)])