Уже несколько месяцев с любопытством гляжу в сторону дистрибутивной семантики — познакомился с теорией, узнал про word2vec, нашёл соответствующую библиотеку для Питона (gensim) и даже раздобыл модель лексических векторов, сформированную по национальному корпусу русского языка. Однако для творческого погружения в материал не хватало душезабирающих данных, которые было бы интересно через дистрибутивную семантику покрутить. Одновременно с этим увлечённо почитывал стишки-пирожки (эдакий синтез задиристых частушек и глубокомысленных хокку) — некоторые даже заучивал наизусть и по случаю угощал знакомых. И вот, наконец, увлечённость и любопытство нашли друг друга, породив воодушевляющую идею в ассоциативных глубинах сознания — отчего бы не совместить приятное с полезным и не собрать из подручных средств какой-нибудь «поэтичный» поисковик по базе пирожков.
из ложных умозаключений
мы можем истину сложить
примерно как перемножают
два отрицательных числа

«Поэтичность» поиска предполагалось реализовать за счёт врождённой способности дистрибутивных векторов показывать степень семантического сходства лексем самым что ни на есть действительным числом (чем меньше угол между векторами слов, тем с большей вероятностью эти слова близки по смыслу — косинусная мера, классика жанра, в общем). Например, «принцесса» и «пастух» гораздо менее близки, чем «пастух» и «овца»: 0.139 против 0.603, что, наверное, логично — вектора национального корпуса должны отражать суровую реальность, а не сказочный мир Г.Х. Андерсена. Способ же расчёта глубины корреляции (диффузии) запроса и пирожка проявился практически сам собой (дёшево и сердито) как нормализованная сумма сходств каждого слова из списка X с каждым словом списка Y (стоп-слова выкидывались, все остальные приводились к нормальной форме, но об этом позже).

Код расчёта семантической диффузии
def semantic_similarity(bag1, bag2: list, w2v_model, unknown_coef=0.0) -> float:
    sim_sum = 0.0
    for i in range(len(bag1)):
        for j in range(len(bag2)):
            try:
                sim_sum += w2v_model.similarity(bag1[i], bag2[j])
            except Exception:
                sim_sum += unknown_coef
    return sim_sum / (len(bag1) * len(bag2))


Результаты поэтического поиска и порадовали, и позабавили. Например, на запрос «музыка» был выдан следующий poem-list:

[('оксане нравилось фламенко'
  'олегу классика и джаз'
  'они вдвоём со сцены пели'
  'про лагеря и мусоров',
  0.25434666007036322),
 ('зашлась в оргазме пианистка'
  'в тумане ноты и рояль'
  'а ей играть ещё фермату'
  'пятнадцать тактов и финал',
  0.19876923472322899),
 ('люблю тебя как шум прибоя'
  'как тёплый ветер как стихи'
  'а толика люблю как танцы'
  'как поцелуи как поспать',
  0.19102709737990775),
 ('мне снится рокот космодрома'
  'и ледяная синева'
  'но я не тычу это людям'
  'об этом песен не пою',
  0.15292901301609391),
 ('индийский танец зита гите'
  'танцует страстно у костра'
  'но не отбрасывает тени'
  'сестра',
  0.14688091047781876)]

Здесь примечательно, что слова «музыка» нет ни в одном пирожке, из занесённых в базу. Однако все пирожковые ассоциации весьма музыкальны и степень их семантической диффузии с запросом довольно высока.

Теперь по порядку о проделанной работе (исходники на GitHub).

Библиотеки и ресурсы


  • Модуль pymorphy2 — для приведения слов к нормальной грамматической форме
  • Модуль gensim — подключение word2vec модели для семантической обработки
  • Так же для работы необходима дистрибутивная модель лексических векторов ruscorpora (320 Мб)

Формирование модели данных


олег представил в виде текста
все что оксана говорит
разбил на главы и абзацы
и на отдельные слова

Первым делом из текстового файла (poems.txt), в котором содержатся стишки-пирожки (порядка восьми сотен), нарезается список, собственно, содержащий эти пирожки в виде строк. Далее из каждого строко-пирожка выжимается мешок слов (bag of words), в котором каждое слово приведено в нормальную грамматическую форму и из которого выкинуты шумовые слова. После чего для каждого мешка вычисляется семантическая «плотность» (интро-диффузия) пирожка и формируется специфический ассоциативный список (помогает понять, какой смысловой слой превалирует с точки зрения модели дистрибутивных векторов). Всё это удовольствие укладывается в словарь под соответствующие ключи и записывается в файл в формате json.

Код выжимания bag of words
def canonize_words(words: list) -> list:
    stop_words = ('быть', 'мой', 'наш', 'ваш', 'их', 'его', 'её', 'их',
                  'этот', 'тот', 'где', 'который', 'либо', 'нибудь', 'нет', 'да')
    grammars = {'NOUN': '_S',
                'VERB': '_V', 'INFN': '_V', 'GRND': '_V', 'PRTF': '_V', 'PRTS': '_V',
                'ADJF': '_A', 'ADJS': '_A',
                'ADVB': '_ADV',
                'PRED': '_PRAEDIC'}

    morph = pymorphy2.MorphAnalyzer()
    normalized = []
    for i in words:
        forms = morph.parse(i)
        try:
            form = max(forms, key=lambda x: (x.score, x.methods_stack[0][2]))
        except Exception:
            form = forms[0]
            print(form)
        if not (form.tag.POS in ['PREP', 'CONJ', 'PRCL', 'NPRO', 'NUMR']
                or 'Name' in form.tag
                or 'UNKN' in form.tag
                or form.normal_form in stop_words):  # 'ADJF'
            normalized.append(form.normal_form + grammars.get(form.tag.POS, ''))
    return normalized


Код формирования модели данных
def make_data_model(file_name: str) -> dict:
    poems = read_poems(file_name)
    bags, voc = make_bags(poems)
    w2v_model = sem.load_w2v_model(sem.WORD2VEC_MODEL_FILE)
    sd = [sem.semantic_density(bag, w2v_model, unknown_coef=-0.001) for bag in bags]
    sa = [sem.semantic_association(bag, w2v_model) for bag in bags]
    rates = [0.0 for _ in range(len(poems))]
    return {'poems'       : poems,
            'bags'        : bags,
            'vocabulary'  : voc,
            'density'     : sd,
            'associations': sa,
            'rates'       : rates}


Общий анализ модели


Самый «твёрдый» пирожок:
убей обиду гнев и похоть
гордыню зависть и тоску
а то что от тебя осталось
из милосердия добей

Плотность, выжимка, ассоциативный список
 0.16305980883482543
['убить_V', 'обида_S', 'гнев_S', 'похоть_S', 'гордыня_S', 'зависть_S', 'тоска_S', 'остаться_V', 'милосердие_S', 'добить_V']
['жалость_S', 'ненависть_S', 'злоба_S', 'ревность_S', 'страх_S', 'страсть_S', 'злость_S', 'стыд_S', 'печаль_S', 'презрение_S']


Ожидаемо в топ «твёрдых» попали пирожки, в которых наличествует много близких по смыслу слов — как синонимичных и так антонимичных (причём нечётко) и без труда обобщаемых в какую-нибудь категорию (в данном случае — это эмоции).

Самый «мягкий» пирожок:
на этом судне мы спасёмся
не будь я прародитель ной
поставьте судно не дурачьтесь
больной

Плотность, выжимка, ассоциативный список
 -0.023802562235525036
['судно_S', 'спастись_V', 'прародитель_S', 'поставить_V', 'дурачиться_V', 'больной_A']
['корабль_S', 'заболевать_V', 'парусник_S', 'больной_S', 'заболеть_V', 'теплоход_S', 'бригантина_S', 'лодка_S', 'припадочный_S', 'бот_S']


Здесь отрицательная плотность, как мне кажется, во многом обусловлена тем, что в ассоциативный список не попал больничный смысл слова «судно». Это вообще одно из слабых мест дистрибутивно-семантических моделей — в них, как правило, одно значение лексемы подавляет популярностью все остальные.

Поисковые запросы по модели


О том как работает поиск, в сущности, было написано выше — пирожки беззатейливо сортируются по уровню их диффузии (обобщённого семантического сходства) со словами запроса.

Код
def similar_poems_idx(poem: str, poem_model, w2v_model, topn=5) -> list:
    poem_bag = dm.canonize_words(poem.split())
    similars = [(i, sem.semantic_similarity(poem_bag, bag, w2v_model))
                for i, bag in enumerate(poem_model['bags'])]
    similars.sort(key=lambda x: x[1], reverse=True)
    return similars[:topn]


Несколько примеров:

Сознание
>> pprint(similar_poems("сознание", pm, w2v, topn=5))
[('олег пытается не думать'
  'но мысли проникают в мозг'
  'скорей всего тому виною'
  'негерметичность головы',
  0.13678271365987432),
 ('моё прекрасно настроенье'
  'красивы тело и лицо'
  'лишь мысли грязные немного'
  'но что поделаешь весна',
  0.1337333519127788),
 ('по логике общаться с зомби'
  'весьма полезней чем с людьми'
  'для них мозги имеют ценность'
  'и важно что у вас внутри',
  0.12728715072640368),
 ('землянин где твоя землянка'
  'не в смысле выемка в земле'
  'а человек с твоей планеты'
  'и выемка внутри него',
  0.12420312280907075),
 ('вы ничего сказала ольга'
  'вы очень даже ничего'
  'ничтожество пустое место'
  'знак ноль на ткани бытия',
  0.11909834879893783)]


Свобода воли
>> pprint(similar_poems("свобода воли", pm, w2v, topn=5))
[('андрей любил немного выпить'
  'а много выпить не любил'
  'но заставлял себя надраться'
  'железной воли человек',
  0.12186796715891397),
 ('убей обиду гнев и похоть'
  'гордыню зависть и тоску'
  'а то что от тебя осталось'
  'из милосердия добей',
  0.10667187095852899),
 ('забудьте слово секс геннадий'
  'у нас в стране не принят секс'
  'у нас альтернатива сексу'
  'у нас любовь и доброта',
  0.10161426827828646),
 ('приятно быть кому то музой'
  'и знать что если бы не ты'
  'его бы творческому дару'
  'кранты',
  0.10136245188273822),
 ('я шла и на меня напали'
  'отняли всё но не смогли'
  'отнять любовь к земле и к людям'
  'и веру в мир и доброту',
  0.098855948557813059)]


Зима
>> pprint(similar_poems("зима", pm, w2v, topn=5))
[('зимой дороги убирают'
  'под грязный снег и гололед'
  'ну а когда зима минует'
  'дороги снова достают',
  0.1875936291758869),
 ('идет безногий анатолий'
  'стоп как же он идет без ног'
  'а так как снег идет как осень'
  'идет за летом в сентябре',
  0.18548772093805863),
 ('илья готовил сани летом'
  'телегу ладил он зимой'
  'так и возился постоянно'
  'кататься он не успевал',
  0.16475609244668787),
 ('захарий смотрит исподлобья'
  'на проходящую весну'
  'на девок бегающих в поле'
  'на трактор тонущий в реке',
  0.14671085483137575),
 ('я не хочу как все в могилу'
  'и в крематорий не хочу'
  'хочу быть скормленным весною'
  'грачу',
  0.13253569027346904)]


Очевидно, что поиск сквозь призму других дистрибутивно-семантических моделей (различные корпуса, алгоритмы обучения, размерности векторов) будет давать другие результаты. В целом технология работает, и работает весьма удовлетворительно. Нечёткий смысловой поиск реализуется легко и беззаботно (по крайней мере, на относительно небольшом объёме данных). В дальнейшем, если дойдут руки и, самое главное, догонит голова, планирую реализовать оценку рейтинга пирожков на основе обучающей выборки. Для начала — простой взвешенной суммой (в роли весового коэффициента будет выступать семантическая диффузия). Потом, возможно, пригодится что-нибудь из machine learning.

Комментарии (41)


  1. rocknrollnerd
    26.01.2016 14:02
    +3

    Черт, вот на чем надо тренировать эти ваши рекуррентные сети. К черту Шекспира, нам нужен генератор пирожков! Не поделитесь, откуда выборку брали и можно ли достать еще?

    По теме — выглядит круто, никогда не занимался текстом, но word2vec издалека выглядел очень интересной штукой. Дилетантский вопрос — а сделать условный шаг дальше и семантически сравнивать предложения/фразы кто-нибудь же наверняка пробовал, да?


    1. drafterleo
      26.01.2016 14:48
      +3

      Пирожки (и порошки :)) надёргал в интернете, сколько было не лень. Даже пришлось небольшой скриптик выдумывть, чтобы отсеять повторы. Честно говоря, сам был бы рад найти увесистый сборник одним файлом, но не нашёл.

      Обрабатывать фразы word2vec, конечно же, уже пробовали (всё украдено до нас :)) — просто сливали несколько слов в одну лексему, а потом всё то же самое. В английском это проще, в русском сложней — у нас, в виду синтетичности языка, многие слова сами по себе уже маленькие предложения, отчего грамматическая нормализация вносит гораздо больше смысловых искажений.


    1. Mayflower
      26.01.2016 18:22
      +2

      На всякий случай — вот сайт с целой кучей пирожков perashki.ru


    1. mihaild
      29.01.2016 01:39
      +1

      Обучил lstm Карпатого на github.com/drafterleo/pie-poem/blob/master/poems.txt. Гласные и строчки считать более-менее научилось, слова — примерно, согласования никакого.

      я был живёшь веселою клей
      я тронангию истязный
      чем банков можно сементами
      стрелы не знала и назвать

      прохожих как внором из солнцев
      возьмите на девять силят
      я надо открываю главку
      и сразу сершия с небюс


      1. rocknrollnerd
        29.01.2016 12:27

        Черт, вы меня опередили) Сколько слоев/нейронов? Я пару ночей гонял два по 512, получается примерно такая же фигня:

        мы все умер и под другой
        тога значит режет стены
        в водьше наступили к куру
        труда не выновить в культор

        кричит олег а под летом
        воя с насон присопяты
        закончится веси беспорность
        а теля понячный продкайся

        с Шекспиром у Карпатого как-то лучше получалось, так что я теперь пробую три слоя)


        1. mihaild
          29.01.2016 14:13

          2 слоя, 128 нейронов


        1. drafterleo
          29.01.2016 19:26

          Нейросеть :)
          >>  pprint(ap.similar_poems("нейросеть", pm, w2v, topn=5))
          [('малошумящий усилитель'
            'для усиления шумов'
            'производимых аппаратом'
            'для шумоподавления',
            0.12743493124366839),
           ('лилит не женщина а просто'
            'эфир лилейной кислоты'
            'по аналогии с боратом'
            'который вовсе не казах',
            0.11525529312273997),
           ('шум квантования пространства'
            'в диапазоне микроволн'
            'наш мир дискретный отличает'
            'от теплых ламповых миров',
            0.10532414661844355),
           ('теоретически я умер'
            'осталось только подогнать'
            'ряд главных функций организма'
            'под этот жесткий постулат',
            0.10308405684535353),
           ('налаживаю генератор'
            'и добиваюсь чтобы ток'
            'был строго синусоидален'
            'как наши встречи с зульфиёй',
            0.10109047862104875)]
          


          1. rocknrollnerd
            29.01.2016 20:07

            Я настолько никогда не занимался текстом, что даже не знаю, что это такое) Плохие результаты на текущем этапе, по крайней мере у меня, кажется, объясняются для начала тем, что я скармливаю сети слишком маленький кусок данных для предсказания следующей буквы (нужно по куску из 20 букв предсказать 21-ю). По той же ссылке на Карпатого у него сотня букв — попробую теперь так)

            Насколько я понимаю, на пальцах это должно работать примерно так — сеть должна держать в памяти такое число знаков, чтобы в него помещалась структура, которую мы хотим воспроизвести. Если говорить только о рифме, то получается, что нужно помнить последние две строки, скажем. Если о смысле — то четыре, и тут мне уже просто интересно, насколько это вообще реально — воспроизвести осмысленные (согласованные) четыре строки подряд.


            1. mihaild
              30.01.2016 02:32

              Только она держит не сами знаки, а какую-то метаинформацию о них (см. картинки).

              Я бы предположил, что проблема еще и в малом размере обучающей выборки (Шекспира было в полтора раза больше).


              1. rocknrollnerd
                30.01.2016 09:17

                Там ниже в комментах привезли еще — вместе получается 1.4 мегабайта примерно.


                1. mihaild
                  30.01.2016 15:32

                  1.4 в UTF8. Т.е. полезного почти в 2 раза меньше.


            1. drafterleo
              30.01.2016 13:24

              Абстрактные грамматики — штука в общем-то простая. По сути, вероятностный генератор (алгоритм) последовательностей символов на марковской цепи (несколько лет назад делал по этой теме программку, правда с уклоном в людей, а не в нейросети :)). Последовательности, сгенерированные разными алгоритмами, классифицируются на раз (через n-граммы или наивным байесом), а вот реконструировать алгоритм по последовательности (т.е. построить изоморфный генератор) — задача куда менее тривиальная. Судя по тому, что я вижу (эксперименты с шекспиром и пирожками), рекуррентные сети должны щёлкать абстрактные грамматики как семечки. По идее — школьная задачка в этой сфере (ведь можно легко проверить результат, посчитать степень корреляции генерируемых последовательностей). Но в сети ничего не нашёл (впрочем, искал не очень глубоко :)). Быть может, вам что-нибудь попадалось об этом?


              1. rocknrollnerd
                30.01.2016 15:51

                О, спасибо за ликбез) Быстрый гуглинг выдал вот такую штуку.


                1. drafterleo
                  01.02.2016 00:51

                  Да, это оно. Взаимное спасибо. Правда, там, насколько я разобрался, основной упор делается на распознавание грамматики, а не на генерацию «фальшивых» (в хорошем смысле этого слова :)) последовательностей. Хотя, если рекуррентная сеть может узнавать, то она, видимо, способна и продуцировать «подделки» малоотличимые от оригинала. Так?


  1. varagian
    26.01.2016 14:04
    +2

    Ещё стоило бы отметить, что дистрибутивная семантика является одним из краегольных камней алгоритмов глубокого обучения (и вообще NN и многих вероятностных моделей), поэтому очень полезно и важно с ней разобраться :-)

    Подробнее можно посмотреть в видео-лекциях школы по глубокому обучению вот тут и ещё можно глянуть крутой курс от Udacity вот тут.


  1. impwx
    26.01.2016 14:17
    +4

    В результаты среди пирожков затесались порошки.


    1. drafterleo
      26.01.2016 14:50
      +1

      Насколько я смог уловить поэтику, «порошок» это искажённое произнесение «пирожка» — вроде как по смыслу то же самое, а по форме немного другое :).


      1. gous32
        26.01.2016 15:34
        +2

        Не совсем так. Пирожок — 9-8-9-8, ямб без рифмы, порошок или порох — 9-8-9-2, с рифмой 2-4, если память не изменяет. Исторически порошки появились из пирожков, но стали вполне себе самостоятельным форматом.
        Есть еще другие похожие формы. Самая распространенная — двустрочная, например:
        зачем учить нас как работать
        вы научитесь как платить
        © bazzlan


        1. drafterleo
          26.01.2016 17:42
          +1

          Вот видите как замечательно, я в порошке увидел озорного сынишку пирожка, а вы узрели воспламеняющий порох. Поэзия однако — стихия субъективной глубины :). В целом, соглашусь, порошки за счёт (неожиданной, как правило) рифмовки «отжигают» подинамичней пирожков. На мой взгляд, если хороший пирожок что-то в душе разминирует, то хороший порошок наоборот — подрывает. Вот мой любимый (и кажется в тему :))

          лишает сна срывает крышу
          и переводит речь на мат
          незапихуемость идей
          в формат

          © ракша


          1. Atos
            26.01.2016 20:50
            +1

            я в порошке увидел озорного сынишку пирожка, а вы узрели воспламеняющий порох.


            хм, а мне тут виделась отсылка к мему «порошок уходи» :)


      1. gous32
        26.01.2016 15:41
        +2

        Вообще, пирожки можно печь на лету, если внутренний голос на ритм настроить. Плохие, но формально — пирожки.
        Настолько просто это делать
        что я в полуночном бреду
        решил скостылить быстро скриптик
        и всех поэтов заменить

        И вообще да, надо в эту сторону подумать. А вы могли бы прислать ваш корпус пирожков для таких целей?


        1. rocknrollnerd
          26.01.2016 15:47
          +1

          В посте есть ссылка. Я тоже прямо заинтересовался)


        1. drafterleo
          26.01.2016 17:49
          +1

          С этими пирожками — главное не объестся. Я вот, чувствую, за последнюю неделю переел. Но всё же, если, вдруг, пополните корпус пирожков — надеюсь на ссылку алаверды :).


  1. skjame
    26.01.2016 18:19
    +1

    Да это же шикарно!!! как только появится свободное время, реализуются подобное у себя на машине и улучшу базу пирожков ^_^


  1. Stas911
    26.01.2016 20:51
    +1

    Очень интересно, спасибо! А по теории что почитать рекомендуете?


    1. drafterleo
      26.01.2016 22:27
      +1

      Откровенно говоря, затрудняюсь ответить, ибо не являюсь большим специалистом в этой области. Если что-то обзорное по дистрибутивной семантике — есть неплохая лекция Андрея Кутузова. Если поразбираться, что под капотом word2vec — вот, например, подробная статья со схемами и матаном.


  1. WerewolfPrankster
    26.01.2016 22:38
    +1

    Как я правильно понимаю похожесть слов «корабль» и «судно» уже встроенны в word2vec?


    1. WerewolfPrankster
      26.01.2016 22:46

      Ай ай, я уже нашел про модель лексических векторов.


      1. drafterleo
        26.01.2016 23:19
        +1

        ;)

        >> w2v.similarity("судно_S", "корабль_S")
        
        0.87323218690957494
        
        >> w2v.most_similar(positive=["судно_S"])
        
        [('корабль_S', 0.873232364654541),
         ('шхуна_S', 0.7688922882080078),
         ('пароход_S', 0.7471548914909363),
         ('катер_S', 0.720923662185669),
         ('крейсер_S', 0.6798930764198303),
         ('парусник_S', 0.6786847114562988),
         ('яхта_S', 0.6684943437576294),
         ('фрегат_S', 0.6651678085327148),
         ('шлюпка_S', 0.6553121209144592),
         ('теплоход_S', 0.6479202508926392)]
        


        1. sebres
          27.01.2016 02:22
          +1

          а что судно — утка? (чисто «научный» интерес))… особенно в сравнении с симили судна с другими водоплавающими (например — гусём)
          и потом корабль с ними же…


          1. drafterleo
            27.01.2016 02:34
            +1

            Утки, гуси, корабли...
            In[23]: w2v.similarity("судно_S", "утка_S")
            Out[23]: 0.089143973072140115
            In[24]: w2v.similarity("судно_S", "гусь_S")
            Out[24]: 0.097027585466394742
            In[25]: w2v.similarity("судно_S", "лебедь_S")
            Out[25]: 0.12152089704781086
            In[26]: w2v.similarity("корабль_S", "утка_S")
            Out[26]: 0.054613116159502359
            In[27]: w2v.similarity("корабль_S", "гусь_S")
            Out[27]: 0.086045645971750101
            In[28]: w2v.similarity("корабль_S", "лебедь_S")
            Out[28]: 0.1518852487994459
            


            1. sebres
              27.01.2016 11:51

              спасибо, надо пощупать…


  1. drafterleo
    28.01.2016 01:43
    +2

    Благодаря стараниям коллеги wiygn (не поленился же человек, наковырял изюму :)) корпус пирожков существенно пополнился (теперь их больше 7500). Мусор я, вроде, вычистил, повторы своими кустарными средствами поудалял, однако если какой-нибудь добрый человек найдёт время перепроверить 1.3 мегабайта чистой поэзии — будет вообще хорошо.

    чистая поэзия :)
    >> pprint(similar_poems("чистая поэзия", pm, w2v, topn=5))
    [('из современной русской прозы'
      'я выделил бы тот роман'
      'который был написан вами'
      'а выделив бы удалил',
      0.13792188721288026),
     ('олегу маша показалась'
      'прекрасной чистой и святой'
      'олег же маше показался'
      'в дырявых бежевых носках',
      0.13690850835700927),
     ('когда любовь переполняет'
      'то выливается она'
      'взаимная посредством секса'
      'а безнадежная в стихах',
      0.12459351854737398),
     ('я томик ленина листаю'
      'страницы гладки и чисты'
      'как кожа юной комсомолки'
      'и также пахнут молоком',
      0.12329326742852674),
     ('зухра великое искусство'
      'она нисходит не ко всем'
      'и те кому она даётся'
      'не все овладевают ей',
      0.11324476203692123)]


    1. hior
      28.01.2016 23:43

      Ух, как интересно. Могу поделиться базой со своего Поэтория. Думаю теперь, вот, реализовать что-то подобное у себя.


      1. drafterleo
        29.01.2016 01:32

        Конечно же делитесь! Это прямо-таки из серии «мечты сбываются» — буквально неделю назад грезил о базе Поэтория :). Кстати, могли бы вы предоставить эту базу вместе с рейтингами — есть огромное желание протащить поэтический материал через машинное обучение на предмет предсказания качества (популярности) пирожка. Поверить, так сказать, алгеброй гармонию — посальерить моцартов :).


        1. hior
          29.01.2016 08:28
          +1

          Надо было не грезить, а написать сразу :) Отправил контакты в личку.


  1. drafterleo
    31.01.2016 19:23
    +2

    Опять-таки при содействии wiygn база пирожков существенно подросла (теперь в ней порядка 33000 штук — poems_33000.txt).

    Примеры «насыщенного» поиска по экзотичным словам:

    Бювар
    >> pprint(ap.similar_poems("бювар", pm, w2v, topn=5, use_associations=True))
    [('у программиста две коробки'
      'коробка а коробка бэ'
      'в коробке а коробка бэ а'
      'в коробке бэ коробка а',
      0.38437933799548024),
     ('так и живёт она с котами'
      'фиалками и сундуком'
      'в котором кожаная плётка'
      'и мой забытый портсигар',
      0.35700261151349105),
     ('карандаши лежат в пенале'
      'пенал в портфеле а портфель'
      'на чердаке среди другого'
      'сентиментального нытья',
      0.34135048477737989),
     ('забыл ключи и ноты тоже'
      'и даже паузы забыл'
      'и что за палочка позвольте'
      'лежит в кармане у меня',
      0.3361660286232277),
     ('олег анальные конфеты '
      'купил и бережно несёт '
      'не в рюкзаке и не в барсетке '
      'и даже не в кармане брюк',
      0.32774677611233893)]