I am trying to generate readable word-like random strings not found in any dictionaries using Markov Chain.
I have pulled a large amount of data of ngram frequencies from a total of 105230 words pulled from GCIDE, and currently these data are stored in Counter
format (serialized as JSON
), and utilizing Markov chain involves randomly choose elements from a set with weights.
I have already found a way to do weighted random sample, like this:
random.choices(keys, weights=values, k=1)
(keys
and values
are pulled from the Counter
)
But all the tutorials I have found are implementing Markov chains using numpy
, and to use this method I need to convert the integers into permillages of the total and ensure the numbers add up to 1.0.
As I said I want the numbers in permillage format (float
with three decimal places) and the float
s must add up to 1.0 in order to make the numpy
method work.
I can convert the numbers into float
s but due to precision limits inherent to the 53-bit double precision floating point format the numbers won't always add up to 1.0.
For example:
initcon = {'c': 7282,
'm': 6015,
'd': 5866,
'p': 5699,
's': 5294,
'b': 4103,
'r': 4097,
'h': 3926,
'l': 3352,
't': 2841,
'f': 2699,
'n': 2171,
'g': 2051,
'pr': 1991,
'v': 1626,
'tr': 1337,
'w': 1337,
'st': 1153,
'ch': 1121,
'cr': 827,
'br': 803,
'j': 799,
'sp': 746,
'gr': 694,
'k': 676,
'ph': 651,
'pl': 645,
'fl': 622,
'th': 594,
'sh': 572,
'q': 553,
'cl': 538,
'fr': 522,
'sc': 516,
'bl': 494,
'gl': 428,
'dr': 421,
'z': 376,
'wh': 338,
'str': 335,
'sl': 325,
'sw': 245,
'rh': 210,
'sk': 167,
'sn': 165,
'scr': 148,
'sm': 143,
'x': 143,
'chr': 141,
'kn': 139,
'thr': 125,
'sq': 124,
'ps': 123,
'wr': 113,
'sch': 106,
'tw': 95,
'spr': 73,
'spl': 72,
'shr': 66,
'sph': 65,
'chl': 54,
'pt': 51,
'gn': 49,
'phl': 41,
'scl': 39,
'gh': 37,
'pn': 37,
'phr': 33,
'kr': 30,
'kl': 22,
'dw': 16,
'kh': 15}
total = sum(initcon.values())
initcon = {k: v/total for k, v in initcon.items()}
print(sum(initcon.values()))
It prints 0.9999999999999999
.
How can I make the numbers in initcon
add up to exactly 1.0 and make them each have exactly 3 decimal places?