
Комментарии 17
Как расслабиться инженеру на работе при помощи Python?
Мой вариант: запрограммировать массажное кресло.
Кейс прекрасный. Ад в номенклатурных справочниках - постоянная проблема. Как-то на одном заводе (на самом деле почти на каждом так) разбирались с неликвидами. А их так процентов 30 запасов, а в деньгах на 1М$ было. Вот то же самое, ага. Так что этот кейс - это "прям деньги". Респект.
Хотя есть небольшая индульгенция у тех, кто "косячит" - они обязаны вводить данные в базу в строгом соответствии с первичным документами. И если ДТ в них указано как "солярка", то в базе данных нужна сшивка-интерпретатор, сохраняющая и бумажные, и "нормализованные" наименования.
Решить ряд идейных проблем кода думаю можно было бы, именно, что подключив к его работе ИИ (промт-инжиниринг), сделав "нейросотрудника", верно интерпретирующего не только части речи, но и общеупотребительные формулировки, учитывая значимость конкретного слова-ключа для идентификации.
Например, то же ДТ, ставшее ТД. Тут не хватает агрегирующего классификатора всех видов топлива. Тогда уровнем ниже был бы дизель(ное), бензин, итд. А на третьем уровне его марка и/или определяющее свойство. На четвертом ГОСТ, ТУ и пр. Т.е. нужно не просто исправить морфологию внутри фразы, но и сделать ее декомпозицию. А потом, если нужно, снова композицию в корректном виде. Но, как правило для решения конкретной бизнес-задачи достаточно второго уровня.
У меня есть замечание и предложение:
Библиотека из вашего кода всё же называется
pymorphy2, аPymorph- это что-то древнее и давно не поддерживаемое, вы явно используете не эту библиотеку. Хорошо бы привести текст в соответствие. И более того, библиотекаpymorphy2уже тоже несколько лет как заброшена, вместо неё теперьpymorphy3, рекомендуется использовать её.Если у вас часто встречаются одинаковые слова, то советую попробовать вынести
morph.parse(word)[0]в отдельную функцию, на которую повесить кеширующий декоратор. Для больших текстов у меня это давало ускорение раз в 10. Но тут сильно зависит от повторяемости слов. Что-то такое:
from functools import lru_cache
@lru_cache
def morph(word):
return morph.parse(word)[0]
Вернее, вы, кажется, используете только .tag.POS от этого, имеет смысл сразу его и возвращать и кешировать тогда:
@lru_cache
def get_pos(word):
return morph.parse(word)[0].tag.POS
...
pos = get_pos(word)
if pos == "PRED":
Хорошее замечание по поводу библиотеки. Да, я использую pymorphy3, это стоит упомянуть.
Как я понял, проект pymorphy2 был заброшен автором ещё в 20-ом году, на github это обсуждали.
Да, декоратор должен дать прирост в скорости
Приятно получить такую критику, в которой все по факту. Спасибо!)
Не нужен там декоратор, просто уберите повторения for word in words:
Добрался до компа, проилюстрирую, кодом.
Просто убрал ненужные циклы. Теперь можно еще объединить одинаковые ветки чтобы упростить код.
def sorting_dictionary(dictionary):
sorted_dic, dic, result_words = [], [], []
for index in dictionary.keys():
sentence_in_cell = dictionary[index].split(", ")
for words in sentence_in_cell:
words = words.split()
for word in words:
p = morph.parse(word)[0]
if p.tag.POS == "NOUN":
sorted_dic.append(word)
elif p.tag.POS == "PREP":
sorted_dic.append(word)
elif p.tag.POS == "ADJF":
sorted_dic.append(word.lower())
elif p.tag.POS in {"CONJ", "PRTF"}:
sorted_dic.append(word)
elif p.tag.POS in {"VERB", "INFN"}:
sorted_dic.append(word)
elif p.tag.POS == None:
sorted_dic.append(word)
words2 = " ".join(sorted_dic)
result_words.append(words2)
words2 = " "
sorted_dic.clear()
res_join = ", ".join(result_words)
dic.append(upcase_first_letter(res_join))
result_words.clear()
return dicДобрый вечер!
В данном случае сортировка слов осуществляться не будет и в словарь перебор слов будет заноситься полностью исходный вариант.
Даже для чистоты эксперимента попробовал Ваш вариант. Помню в самом начале написания я хотел как-то избавиться от вложенных циклов, но не получилось, т.к. нужно перебрать каждое слово и внести его в определенной последовательности.
И также на производительность никак не сказалось, а вот декоратор предложенный CrazyElf помог.
Теперь понял вашу логику. Можно через сортировку попробовать. Сначала собрать все пары тэг значение в словарь и потом отсортировать.
ORDER = ["NOUN", "PRED"]
def get_key(pair):
k, _ = pair
if k in ORDER:
return ORDER.index(k)
else:
return len(ORDER)
def sort_words(word_pairs):
return [word for _, word in sorted(word_pairs, key=get_key)]
if __name__ == '__main__':
print(sort_words(
[("NOUN", "хомяк" ), ("PRED", "в")]
))
print(
sort_words(
[("PRED", "в"), ("NOUN", "хомяк"), ]
))Только что проверил, как и ожидалось, декоратор дал прирост, но совсем немного в 2-3 секунды!) Из выгрузки, которая описывалась в статье.
Думаю результат будет более заметным, если выгрузка будет объемнее.
А как фильтрануть "лампа гОлАгеговая". Или "ОсСциЛограф"?)))
К сожалению, от опечаток никто не застрахован, особенно инженера на производстве, когда все делается на скорую руку.
Библиотека pymorph3 слова с ошибками: "голагеговая" и "оссцилограф" определяет как надо - прилагательное и существительное соответственно.
Что касается орфографии, к счастью, в Excel есть словарь, который можно запустить для проверки.
Если взять к примеру опечатку из выгрузки "Газы реакции/ котловая вода", то именно слово вместе со слэшем "реакции/" pymorph3 не сможет определить и выдаст результат, как UNKN, то есть токен не удалось распознать.
В этом случае перебор будет отличаться от входящего значения, и при сравнении измененных позиций сразу станет понятно (сразу скажу таких случаев было немного)
Лично я просматривал измененные позиции, что позволило вдобавок ещё навести красоту и отредактировать рабочую среду.
Скорость работы алгоритма составила 29 секунд.
Давно скорость измеряется в секундах? Тогда уж "время работы алгоритма — 29 секунд."
Как расслабиться инженеру на работе при помощи Python?