pymorphy2
pymorphy2 copied to clipboard
Склонение имен человеческих
Всем привет,
нигде в доках не смогли найти примера, какие граммемы лучше использовать для склонения имен. Мы поигрались с разными вариантами, но они лажают на имени "Алла" в дательном падеже.
name = u'Алла'
pname = morth.parse(name)[0]
dname = pname.inflect( set(['datv', 'sing', 'femn', "Name"] ) )
- возвращает "Алла" вместо ожидаемого "Алле".
Как исправить?...
Привет.
С Аллой небольшая тонкость: там 2 разбора, мужское имя "Алл" и женское "Алла"; разборы никак не связанные. Так получается, что Алл выдается первым - видимо, имя Алла не встречалось в части OpenCorpora со снятой неоднозначностью, и поэтому pymorphy2 пока не знает, что Алла - значительно более распространенное имя, чем Алл. Выдает первое попавшееся, и им оказывается Алл.
Дальше, вы выбираете этот разбор кодом pname = morth.parse(name)[0] - берете первый, это Алл. И затем уже склоняете его == пытаетесь найти вариант имени Алл дательного падежа ед.ч. женского рода. Имени Алл женского рода не бывает, поэтому pymorphy2 позвращает ближайший вариант (дательный падеж ед. ч. мужского рода).
Т.е. корень проблемы в том, что изначально вы выбрали не то имя для склонения ([0]). Если выбрать [2], то все должно заработать.
Дальше вопрос - как выбирать нужный разбор для склонения автоматически. Тут такие соображения:
- Если вы знаете, что на входе - имя единственного числа именительного падежа, то можно отсеять варианты в косвенных падежах (в данном случае -
[1]), варианты во мн.ч. и варианты без граммемы Name. - Если вы знаете пол, то можно отсеять варианты с другим полом. Т.е. граммему femn можно не в inflect передавать (слова по родам все равно через inflect не склоняются), а отфильтровывать с ее помощью исходные разборы.
- Если вы знаете, что на входе имя, то можно сортировать исходные варианты разборов по частотности имен; для этого нужно найти где-нибудь соответствующий список имен с частотами.
В pymorphy2 из этого пока ничего не встроено. Есть сортировка по частотности разборов (3), но там пока достаточно мало слов с данными, только самые распространенные, и ничего специфичного для имен.
В pymorphy1 метод inflect был немного более высокоуровневым - он на основе переданных граммем сам выбирал нужный разбор (предпочитал разборы в именительном падеже и те, у которых больше граммем из того, что в inflect передано). Но это лишь один из подходов (соответствует пункту (2)); в общем случае нельзя правильно просклонять слово, не зная, что это за слово, не сняв неоднозначность разбора. Снимать неоднозначность можно по-разному: по частотам отдельных слов (знаем, что Алл - очень редкое имя), по особенностям задачи (знаем, что на входе женское имя в именительном падеже), по соседним словам (например, склоняется часть предложения, и из нее понятно, что Алла - это имя женского рода).
В pymorphy2 можно добавить склонение имен отдельной функцией/классом "из коробки" - думаю, добавить список частот имен и реализовать какую-то логику по выбору правильного разбора - учитывать частоту, принимать доп. информацию - пол, например, считать, что на входе слово в и.п. Вроде этого:
>>> m = MorphAnalyzer()
>>> inflector = FirstNameInflector(m) # , name_frequences
>>> inflector.inflect(u'Алла', {"datv"}) # , {'datv', 'masc'}
'Алле'
Пулл-реквесты приветствуются)
Идея понятна. Тогда очень помогло бы если не изменение алгоритма, то твик его в части Score. Сейчас там везде по 0.33 (в случае Аллы). А вообще-то было бы хорошо поднимать Score у вариантов, максимально совпавших с нашими входными граммемами. Для этого в parse надо добавить опциональный список граммем и сравнивать с ним. Чем больше совпадений, тем больше Score. Мы же заранее знаем, что Алла это Noun, Name, sing, femn. Почему бы парсеру не учесть наши знания при выставлении Score?
На каждый чих писать FirstNameInflector, LastNameInflector, KittyNameInflector и т.д. писать замучаешься. Входные граммемы покрывают все эти задачи.
FirstNameInflector будет работать лучше, чем inflect с граммемами, если, например, пол неизвестен. Там везде есть свои особенности. Те же фамилии в словарь все добавить нельзя, и склоняются они не так, как "обычные" слова. Хотя если б pymorphy2 предсказывал вариант разбора с Surn для бОльшего числа фамилий, передача Surn бы работала..
Против добавления "общего" метода для склонения я не против. Его можно в MorphAnalyzer добавить - он бы, видимо, пробовал склонять все варианты разбора и искал вариант склонения, наиболее близкий к запрашиваемой форме. И/или принимал бы подсказку про исходные граммемы. Пулл-реквесты, опять таки, приветствуются.
Score трогать не хочу, cейчас для словарных слов у него есть вполне конкретное значение - это вероятность P(разбор | слово), оцененная по части OpenCorpora со снятой неоднозначностью, с использованием сглаживания Лапласа; сортировка/фильтрация на основе граммем только в методе inflect нужена, никаких причин "вклиниваться" в Parse.score (вместо использования отдельной локальной переменной) вроде нет.
Да можно и написать :), единственное над чем пока лень думать это функция близости двух массивов. Там ведь не только пересечение по общим элементам, но и разные элементы могут иметь разный вес....
Мне кажется, что про веса для граммем можно не думать пока, т.к. подобранные "от балды" веса ничем не лучше единичных весов, а чтоб подбирать их исходя из каких-то данных, нужны эти самые данные, которых нет и непонятно, как получить.
Вместо "весов" по граммемам я бы брал склоненный вариант первого по порядку подходящего разбора, т.к. разборы уже отсортированы хотя бы по score.
См., кстати, https://github.com/kmike/pymorphy2/commit/530337ef0b28031886ab1b04008def1c42edf1d1#diff-c0063732e61bc64462e1c32836782f55L413 - я похожий метод когда-то прибил, т.к. он был недоделанный.