Марковские цепи помогут вычислить сочетаемость букв в именах, и выбирать наиболее "благозвучную" букву по контексту (префиксу).
Метод архиэффективный и способен породить бесконечннешее количество слов.
Но только если обучающая выборка достаточно большая.
Мои рекомендации:
Используйте длинну префикса 3-4 буквы (примерно длинна слога).
Боле длинные префиксы будут порождать слова слишком похожие на исходные и их рекомбинации.
Более короткие будут не очень благозвучны.
Обязательно используйте символы начала и конца слова в качестве спец-буквы ('^' и '$'), просто пробела недостаточно, но уже не помню почему.
Для имён имеет смысл генерить их с конца, поскольку окончания у имён специфичные, и рандом может долго не попадать на концевую цепочку, порождая излишне длинные слова. А при генерации с конца можно просто по критической длинне принудительно оборвать слово, или выйти на ближайшей остановке.
Для хранения эффективно использовать префиксное дерево с частотами в качесве значений.
Алгоритм составления словаря довольно простой:
prefix = '^'
for letter in text:
freqdict[prefix+ letter] += 1 # увеличение счётчика этого сочетания
if letter ='$': # конец слова, сброс префикса
prefix = '^'
else:
prefix = prefix[-depdth:] # обрезане префикса до максимальной длинны
После этого нужно нормальизовать значения для каждого префикса, чтобы
для каждого префикса сумма значений всех хвостов была = 1.
При таком раскладе можно "склеить" частоты в единичный отрезок, разделёный на части пропорционально частоте, и рандомом выбирать "взвешенно-равномерно".
Алгоритм генерации:
prefix = '^'
while prefix[-1] != '$':
tails = freqdict[prefix].items() # под-дерево всех продолжений префикса в виде списка (key, value)
thresh = random() # точка на единичном отрезке
i = 0 # текущий элемент
level = 0 # верхняя граница отрезка текущего элемента
while thresh > level:
level += tails[i][1]
i++
prefix += tails[i][0]
Код написан по памяти, не принимайте на слово :)
Наверно, мне уже пора выкладывать библиотеку для рыбогенерации...