def test_pipeline_key(): from yargy.pipelines import morph_pipeline pipeline = morph_pipeline([ 'закрытое общество', 'завод' ]) F = fact('F', ['a']) RULE = pipeline.interpretation( F.a.normalized() ).interpretation( F ) parser = Parser(RULE) match = parser.match('закрытом обществе') record = match.fact assert record == F(a='закрытое общество') RULE = pipeline.interpretation( normalized() ) parser = Parser(RULE) match = parser.match('заводе') value = match.fact assert value == 'завод'
def test_pipeline(): RULE = rule( pipeline(['a b c', 'b c']), 'd' ) parser = Parser(RULE) assert parser.match('b c d') assert parser.match('a b c d') RULE = rule( pipeline(['a b']).repeatable(), 'c' ) parser = Parser(RULE) assert parser.match('a b a b c') RULE = rule( caseless_pipeline(['A B']), 'c' ) parser = Parser(RULE) assert parser.match('A b c') RULE = morph_pipeline([ 'текст', 'текст песни', 'материал', 'информационный материал', ]) parser = Parser(RULE) matches = list(parser.findall('текстом песни музыкальной группы')) assert len(matches) == 1 match = matches[0] assert [_.value for _ in match.tokens] == ['текстом', 'песни'] matches = list(parser.findall('информационного материала под названием')) assert len(matches) == 1 match = matches[0] assert [_.value for _ in match.tokens] == ['информационного', 'материала'] RULE = morph_pipeline(['1 B.']) parser = Parser(RULE) assert parser.match('1 b .')
def getTags(text, tag_list): if text == None: return {} RULE = morph_pipeline(tag_list) mentioned_tags = [] parser = Parser(RULE) morph = pymorphy2.MorphAnalyzer() for match in parser.findall(text): try: value = match.tokens[0].value normalized_value = morph.parse(value)[0].normal_form if normalized_value in mentioned_tags: continue mentioned_tags.append(normalized_value) except: print('Salary parser error') return mentioned_tags
def test_pipeline_key(): from yargy.pipelines import morph_pipeline pipeline = morph_pipeline(['закрытое общество', 'завод']) F = fact('F', ['a']) RULE = pipeline.interpretation(F.a.normalized()).interpretation(F) parser = Parser(RULE) match = parser.match('закрытом обществе') record = match.fact assert record == F(a='закрытое общество') RULE = pipeline.interpretation(normalized()) parser = Parser(RULE) match = parser.match('заводе') value = match.fact assert value == 'завод'
def extract(text): with open(os.path.join(os.getcwd(), 'list_diseases\\diseases'), encoding='UTF-8') as f: diseases = f.read().split('\n') text = text.replace('\ufeff', '') text = text.replace('\n', ' \n ') text = text.replace('\\', ' ') symptoms = ['Дата рождения', 'Дата осмотра','Дата заболевания', 'Возраст', 'Болен дней','Болен часов','Возраст в днях','Время поступления', 'Время заболевания', 'рост','вес', 'IMT', 'давление диаст', 'давление сист', 'температура поступления','мах температура', 'Т-Ан01', 'Т-Ан03', 'пол', 'др заболевания в анамнезе', 'кем направлен', 'побочное действие лекартсв','аллергическая реакция', 'озноб', 'слабость', 'вялость','головная боль', 'нарушение сна', 'нарушение аппетита', 'ломота','тошнота', 'нарушение сознания', 'Судороги', 'Парестезии', 'эритема', 'с четкими границами', 'валик', 'боль','Гиперемия', 'Отек', 'Лимфаденит', 'Лимфангит', 'квартира, дом','контакт с зараженными','речная рыба','провоцирущие факторы', 'предрасполагающие факторы','кол-во сопут заболеваний','соц категория','сопутствующий диагноз','основной диагноз', 'контакт с зараженными', 'пищевой анамнез', 'раневые ворота', 'аллергия на лекарства', 'клещ', 'географический анамнез', 'вредные привычки', 'домашние животные', 'условия труда','избыточное питание', 'ППТ', 'ЛПТ', 'бытовые условия', 'питание', 'интоксикация', 'ЧСС'] dict_symp = dict.fromkeys(symptoms) # In[5]: dates_lst = [] DAY = and_( gte(1), lte(31) ) MONTH = and_( gte(1), lte(12) ) YEAR = and_( gte(1), lte(19) ) YEARFULL = and_( gte(1900), lte(2020) ) DATE = or_( rule(YEAR,'.',MONTH,'.',DAY), rule(DAY,'.',MONTH,'.',YEAR), rule(DAY,'.',MONTH,'.',YEARFULL), rule(DAY,'.',MONTH), rule(DAY,'.',MONTH,YEARFULL), rule(DAY,'.',MONTH,YEAR)) parser = Parser(DATE) for match in parser.findall(text): dates_lst.append(''.join([_.value for _ in match.tokens])) if int(dates_lst[1][-2:])-int(dates_lst[0][-2:])<0: dict_symp['Дата рождения'] = dates_lst[0] dict_symp['Дата осмотра'] = dates_lst[1] dict_symp['Дата заболевания'] = dates_lst[2] else: birth = None dict_symp['Дата осмотра'] = dates_lst[0] dict_symp['Дата заболевания'] = dates_lst[1] if len(dict_symp['Дата заболевания'])==5: dict_symp['Дата заболевания'] += dict_symp['Дата осмотра'][dict_symp['Дата осмотра'].rfind('.'):] TYPE = morph_pipeline(['дней']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0 and dict_symp['Дата заболевания'] is None: dict_symp['Дата заболевания'] = text[lst[0][0][0]-20:lst[0][0][0]+20] dict_symp['Дата заболевания'] = re.findall(r'\d+', dict_symp['Дата заболевания'])[0] dict_symp['Дата заболевания'] = str(int(dict_symp['Дата осмотра'][:2])-int(dict_symp['Дата заболевания'])) dict_symp['Дата заболевания'] = dict_symp['Дата заболевания']+dict_symp['Дата осмотра'][2:] age_lst = [] AGE = and_( gte(0), lte(100) ) AGE_RULE = or_(rule("(",AGE,")"), rule(gram('ADJF'),",",AGE)) parser = Parser(AGE_RULE) for match in parser.findall(text): s = ''.join([_.value for _ in match.tokens]) age_lst.append((re.findall(r'\d+', s)[0])) if len(age_lst)>0: dict_symp['Возраст'] = age_lst[-1] try: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%Y') except: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%y') d1 = d1.strftime('%d.%m.%Y') d1 = datetime.strptime(d1, '%d.%m.%Y') try: d2 = datetime.strptime(dict_symp['Дата заболевания'], '%d.%m.%Y') except: d2 = datetime.strptime(dict_symp['Дата заболевания'], '%d.%m.%y') d2 = d2.strftime('%d.%m.%Y') d2 = datetime.strptime(d2, '%d.%m.%Y') dict_symp['Болен дней'] = (d1 - d2).days dict_symp['Болен часов'] = (int(dict_symp['Болен дней'])-1)*24 if dict_symp['Дата рождения'] is None: dict_symp['Возраст в днях'] = int(dict_symp['Возраст'])*365 else: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%Y') d2 = datetime.strptime(dict_symp['Дата рождения'], '%d.%m.%Y') dict_symp['Возраст в днях'] = (d1 - d2).days time_lst = [] HOURS = and_( gte(0), lte(59) ) MINUTES = and_( gte(0), lte(59) ) TIME = or_(rule(HOURS,':',MINUTES), rule(not(normalized('.')),HOURS, normalized('час')),) parser = Parser(TIME) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) s = s.replace('часов', ':00') s = s.replace('час', ':00') time_lst.append(s) if len(time_lst)>0: dict_symp['Время поступления'] = time_lst[0] dict_symp['Время заболевания'] = time_lst[0] if len(time_lst)>1: dict_symp['Время заболевания'] = time_lst[1] t1 = dict_symp['Время поступления'] t2 = dict_symp['Время заболевания'] delta = int(t1[:t1.find(':')])+24-int(t2[:t2.find(':')]) dict_symp['Болен часов'] = dict_symp['Болен часов'] + delta HEIGHT = and_( gte(50), lte(250) ) WEIGHT = and_( gte(10), lte(150) ) HEIGHT_RULE = or_(rule(normalized('рост'),'-',HEIGHT), rule(normalized('рост'),':',HEIGHT), rule(normalized('рост'),HEIGHT)) WEIGHT_RULE = or_(rule(normalized('вес'),'-',WEIGHT), rule(normalized('вес'),':',WEIGHT), rule(normalized('вес'),WEIGHT)) s='' parser = Parser(HEIGHT_RULE) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) s = re.findall(r'\d+', s)[0] if s != '': dict_symp['рост'] = int(s) s = '' parser = Parser(WEIGHT_RULE) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) s = re.findall(r'\d+', s)[0] if s != '': dict_symp['вес'] = int(s) if (dict_symp['рост'] is not None) and (dict_symp['вес'] is not None): dict_symp['IMT'] = round(dict_symp['вес']/(dict_symp['рост']/100*dict_symp['рост']/100),2) ADSIST = and_( gte(50), lte(250) ) ADDIAST = and_( gte(20), lte(200) ) PRES = or_(rule('АД', ADSIST,'/',ADDIAST), rule('АД', ADSIST,ADDIAST), rule('АД', ADSIST, ':',ADDIAST), rule('АД','-', ADSIST, '/',ADDIAST), rule('А/Д', ADSIST, '/',ADDIAST), rule('А/Д', ADSIST, ADDIAST), rule('А/Д',' ', ADSIST, '/',ADDIAST), rule(ADSIST, '/',ADDIAST)) s = '' parser = Parser(PRES) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) s = re.findall(r'\d+', s) if len(s)>1: dict_symp['давление сист'] = s[0] dict_symp['давление диаст'] = s[1] PULSE = and_( gte(40), lte(150) ) PRES = or_(rule('ЧСС','-',PULSE), rule('ЧСС',PULSE), rule('ЧСС','/',PULSE), rule('пульс',PULSE),) s = '' parser = Parser(PRES) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) s = re.findall(r'\d+', s) if len(s)>0: dict_symp['ЧСС'] = s[0] status = text[text.find('Объективный статус'): text.find('Объективный статус')+text[text.find('Объективный статус')+1:].find(' \n \n')] DEGREES = and_( gte(34), lte(42) ) SUBDEGREES = and_( gte(0), lte(9) ) TEMP = or_(rule(DEGREES,',',SUBDEGREES), rule(DEGREES,'.',SUBDEGREES), rule(DEGREES)) temp_lst = [] parser = Parser(TEMP) for match in parser.findall(status): temp_lst.append(''.join([_.value for _ in match.tokens])) if len(temp_lst)>0: dict_symp['температура поступления'] = temp_lst[0] temp_lst = [] parser = Parser(TEMP) for match in parser.findall(text): temp_lst.append(''.join([_.value for _ in match.tokens])) if len(temp_lst)>0: if dict_symp['температура поступления'] is None: dict_symp['температура поступления'] = temp_lst[0] dict_symp['мах температура'] = max([float(i.replace(',','.')) for i in temp_lst]) if dict_symp['мах температура']>38: dict_symp['Т-Ан01'] = 1 else: dict_symp['Т-Ан01'] = 0 if dict_symp['мах температура']>40: dict_symp['Т-Ан03'] = 3 elif dict_symp['мах температура']>39: dict_symp['Т-Ан03'] = 2 elif dict_symp['мах температура']>38: dict_symp['Т-Ан03'] = 1 else: dict_symp['Т-Ан03'] = 0 sex_lst = [] SEX_RULE = or_(rule(normalized('женский')), rule(normalized('мужской'))) parser = Parser(SEX_RULE) for match in parser.findall(text): sex_lst.append(''.join([_.value for _ in match.tokens])) dict_symp['пол'] = sex_lst[0] dict_symp['пол'] = dict_symp['пол'].lower().replace('женский', '2') dict_symp['пол'] = dict_symp['пол'].lower().replace('мужской', '1') TYPE = morph_pipeline(diseases[:-1]) anamnez = text[text.find('Анамнез'): text.find('Анамнез')+text[text.find('Анамнез')+1:].rfind('Анамнез')] anamnez = anamnez.replace('туберкулез',' ') anamnez = anamnez.replace('туберкулёз',' ') family = anamnez[anamnez.find('Семейный'):anamnez.find('Семейный')+60] anamnez = anamnez.replace(family,' ') anamnez = anamnez.replace('описторхоз',' ') dis_lst = [] parser = Parser(TYPE) for match in parser.findall(anamnez): dis_lst.append(' '.join([_.value for _ in match.tokens])) op_rule = or_(rule(normalized('описторхоз'), not_(normalized('не')))) parser = Parser(op_rule) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dis_lst.append(' описторхоз') tub_rule = rule(normalized('туберкулез'), not_(normalized('отрицает'))) parser = Parser(tub_rule) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dis_lst.append(' туберкулез') dict_symp['др заболевания в анамнезе'] = ', '.join(dis_lst) dict_symp['др заболевания в анамнезе'] = morph.parse(dict_symp['др заболевания в анамнезе'])[0].normal_form TYPE = morph_pipeline(['Поликлиника',"скорая помощь", "ск/помощь", 'СМП', "обратился"]) napr = None napr_lst = [] parser = Parser(TYPE) for match in parser.findall(text): napr_lst.append(' '.join([_.value for _ in match.tokens])) if len(napr_lst)>0: napr = napr_lst[-1] napr = morph.parse(napr)[0].normal_form if napr == "обратиться": dict_symp['кем направлен'] = 3 elif napr == "скорая помощь" or napr == "ск/помощь" or napr == 'смп'or napr == "ск / помощь" or napr == "скорой помощь" or napr == "скорую помощь": dict_symp['кем направлен'] = 1 elif napr == "поликлиника": dict_symp['кем направлен'] = 2 ALLERG_RULE = or_(rule(normalized('Аллергическая'),normalized('реакция'), normalized('на'), gram('NOUN').optional().repeatable(), gram('ADJF').optional().repeatable()), rule(normalized('Аллергическая'),normalized('реакция'), normalized('на'), gram('NOUN').optional().repeatable(), gram('ADJF').optional().repeatable(), '"', gram('ADJF').optional().repeatable(), gram('NOUN').optional().repeatable(), '"'), rule(normalized('Аллергическая'),normalized('реакция'), normalized('на'), gram('NOUN').optional().repeatable(), gram('ADJF').optional().repeatable(),',', gram('NOUN').optional().repeatable(), gram('ADJF').optional().repeatable(),',',gram('NOUN').optional().repeatable(), gram('ADJF').optional().repeatable()), rule(normalized('Аллергическая'),normalized('реакция'), normalized('на'), gram('ADJF').optional(),gram('NOUN').optional().repeatable())) parser = Parser(ALLERG_RULE) for match in parser.findall(text): item = (' '.join([_.value for _ in match.tokens])) dict_symp['аллергическая реакция'] = item[item.find('на')+3:] if dict_symp['аллергическая реакция'] is not None: dict_symp['побочное действие лекартсв'] = 1 dict_symp['аллергия на лекарства'] = 1 symptoms = [['озноб', 'познабливание'], 'слабость', 'вялость','головная боль', 'нарушение сна', 'нарушение аппетита', 'ломота', 'тошнота', 'нарушение сознания','Судороги', 'Парестезии', 'эритема', ['с четкими границами', 'границами четкими' , 'четкими неровными краями','с четкими краями', 'краями четкими' , 'четкими неровными краями'], 'валик', 'боль',['Гиперемия', 'гиперемирована'], 'Отек', 'Лимфаденит', 'Лимфангит'] for i in symptoms: lst = [] if isinstance(i, str): TYPE = morph_pipeline([i]) else: TYPE = morph_pipeline(i) parser = Parser(TYPE) for match in parser.findall(text): lst.append(' '.join([_.value for _ in match.tokens])) if len(lst)>0: if isinstance(i, str): dict_symp[i]=1 else: dict_symp[i[0]]=1 else: if isinstance(i, str): dict_symp[i]=0 else: dict_symp[i[0]]=0 # In[20]: TYPE = morph_pipeline(['географический', 'выезжал']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-40:match.span[1]+40] geo_rule = rule(not_(normalized('не')),normalized('выезжал')) parser = Parser(geo_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['географический анамнез'] = 1 else: dict_symp['географический анамнез'] = 0 TYPE = morph_pipeline(['бытовые']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-30:match.span[1]+30] cond_rule = rule(not_(normalized('не')),normalized('удовлетворительные')) parser = Parser(cond_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['бытовые условия'] = 1 else: dict_symp['бытовые условия'] = 0 TYPE = morph_pipeline(['условия труда']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-20:match.span[1]+20] cond_rule = rule(not_(normalized('не')),normalized('удовлетворительные')) parser = Parser(cond_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['условия труда'] = 1 else: dict_symp['условия труда'] = 0 TYPE = morph_pipeline(['питание']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-20:match.span[1]+20] food_rule = or_(rule(not_(normalized('не')),normalized('удовлетворительное')), rule(not_(normalized('не')),normalized('полноценное'))) parser = Parser(food_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['питание'] = 1 else: dict_symp['питание'] = 0 food_rule = rule(not_(normalized('не')),normalized('избыточное')) parser = Parser(food_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['избыточное питание'] = 1 else: dict_symp['избыточное питание'] = 0 TYPE = morph_pipeline(['рыба']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-40:match.span[1]+40] TYPE = morph_pipeline(['да', 'постоянно']) parser = Parser(TYPE) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['речная рыба'] = 1 fish_rule = rule(not_(normalized('не')),normalized('употребляет')) parser = Parser(fish_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['речная рыба'] = 1 else: dict_symp['речная рыба'] = 0 TYPE = morph_pipeline(['контакт']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-40:match.span[1]+40] TYPE = morph_pipeline(['да']) parser = Parser(TYPE) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['контакт с зараженными'] = 1 else: dict_symp['контакт с зараженными'] = 0 lst = [] TYPE = morph_pipeline(['рана', "раневые ворота", "входные ворота"]) parser = Parser(TYPE) for match in parser.findall(text): lst.append(' '.join([_.value for _ in match.tokens])) if len(lst)>0: dict_symp["раневые ворота"] = 1 else: dict_symp["раневые ворота"] = 0 lst = [] TYPE = morph_pipeline(['интоксикация']) parser = Parser(TYPE) for match in parser.findall(text): lst.append(' '.join([_.value for _ in match.tokens])) if len(lst)>0: dict_symp["интоксикация"] = 1 else: dict_symp["интоксикация"] = 0 lst = [] TYPE = morph_pipeline(['клещ', "присасывание"]) parser = Parser(TYPE) for match in parser.findall(text): lst.append(' '.join([_.value for _ in match.tokens])) if len(lst)>0: dict_symp["клещ"] = 1 else: dict_symp["клещ"] = 0 TYPE = morph_pipeline(['сырой воды']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-80:match.span[1]+80] TYPE = morph_pipeline(['не было', 'отрицает', 'нет']) parser = Parser(TYPE) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['пищевой анамнез'] = 0 else: dict_symp['пищевой анамнез'] = 1 TYPE = morph_pipeline(['вредные привычки', 'алкоголь']) parser = Parser(TYPE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: text_fish = text[match.span[1]-80:match.span[1]+80] TYPE = morph_pipeline(['не было', 'отрицает', 'нет', 'не употребляет']) parser = Parser(TYPE) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['вредные привычки'] = 0 else: dict_symp['вредные привычки'] = 1 smoke_rule = or_(rule(not_(normalized('не')),normalized('курит')), rule(not_(normalized('не')),normalized('употребляет'))) parser = Parser(smoke_rule) lst = [] for match in parser.findall(text_fish): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['вредные привычки'] = 1 home = None home_types = [['бездомный'], ['дом благоустроенный'], ['дом не благоустроенный','дом неблагоустроенный'], ['квартира не благоустроенная', 'квартира неблагоустроенная'], ['квартира благоустроенная'],] for i in range(len(home_types)): home_lst = [] TYPE = morph_pipeline(home_types[i]) parser = Parser(TYPE) for match in parser.findall(text): home_lst.append(' '.join([_.value for _ in match.tokens])) if len(home_lst)>0: home = i dict_symp['квартира, дом'] = home pets = [] pet_types = [['кошка'], ['собака'], ['корова','коза']] for i in range(len(pet_types)): pet_lst = [] TYPE = morph_pipeline(pet_types[i]) parser = Parser(TYPE) for match in parser.findall(text): pet_lst.append(' '.join([_.value for _ in match.tokens])) if len(pet_lst)>0: pets.append(i+1) if len(pets)>1: pets = 4 elif len(pets)>0: pets = pets[0] else: pets = 0 dict_symp['домашние животные'] = pets factors = [] factor_types = [['ссадины',"царапины", "раны", "расчесы", "уколы", "потертости", "трещины", 'вскрытие'], ['ушибы'], ['переохлаждение','перегревание','смена температуры'], ['инсоляция'], ['стресс'], ['переутомление']] for i in range(len(factor_types)): factor_lst = [] TYPE = morph_pipeline(factor_types[i]) parser = Parser(TYPE) for match in parser.findall(text): factor_lst.append(' '.join([_.value for _ in match.tokens])) if len(factor_lst)>0: factors.append(i+1) dict_symp['провоцирущие факторы'] = factors factors = [] factor_types = [['микоз',"диабет", "ожирение", "варикоз", "недостаточность", "лимфостаз", "экзема"], ['тонзилит',"отит", "синусит", "кариес", "пародонтоз", "остеомиелит", "тромбофлебит", "трофические язвы"], ['резиновая обувь','загрязнения кожных'], ['соматические заболевания']] for i in range(len(factor_types)): factor_lst = [] TYPE = morph_pipeline(factor_types[i]) parser = Parser(TYPE) for match in parser.findall(text): factor_lst.append(' '.join([_.value for _ in match.tokens])) if len(factor_lst)>0: factors.append(i+1) dict_symp['предрасполагающие факторы'] = factors lst = [] TYPE = morph_pipeline(['работает']) parser = Parser(TYPE) for match in parser.findall(text): lst.append(' '.join([_.value for _ in match.tokens])) if len(lst)>0: dict_symp['соц категория'] = 0 soc_rule = rule(not_(normalized('не')),normalized('работает')) parser = Parser(soc_rule) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['соц категория'] = 1 DIAGNOZ_RULE = or_(rule(normalized('сопутствующий'), not_(or_(gram('NOUN')))), rule(normalized('сопутствующий'),normalized('диагноз')), rule(normalized('диагноз'),normalized('сопутствующий')),) rules = ['сопутствующий', 'сопутствующий диагноз', 'диагноз сопутствующий'] TYPE = morph_pipeline(rules) parser = Parser(DIAGNOZ_RULE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: dict_symp['сопутствующий диагноз'] = text[match.span[1]+2:match.span[1]+text[match.span[1]:].find(' \n \n')] dict_symp['кол-во сопут заболеваний'] = dict_symp['сопутствующий диагноз'].count('\n') if dict_symp['кол-во сопут заболеваний']==0: dict_symp['кол-во сопут заболеваний']=1 DIAGNOZ_RULE = or_(rule(normalized('диагноз'),normalized('при'),normalized('поступлении')), rule(normalized('клинический'),normalized('диагноз')), rule(normalized('диагноз'),normalized('клинический')), rule(normalized('основной'),normalized('диагноз')), rule(normalized('диагноз'),normalized('основной')), rule(normalized('Ds')), rule(not_(or_(gram('ADJF'),gram('NOUN'))),normalized('диагноз'),not_(or_(gram('ADJF'),gram('PREP'))))) lst = [] parser = Parser(DIAGNOZ_RULE) for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) last = match.span[1]+text[match.span[1]:].find(' \n \n') if last == match.span[1]-1: last = len(text)-1 dict_symp['основной диагноз'] = text[match.span[1]+1:last] # In[38]: TYPE = morph_pipeline(['левая', 'слева']) parser = Parser(TYPE) lst = [] for match in parser.findall(dict_symp['основной диагноз']): lst.append((match.span, [_.value for _ in match.tokens])) TYPE = morph_pipeline(['правая', 'справа']) parser = Parser(TYPE) for match in parser.findall(dict_symp['основной диагноз']): lst.append((match.span, [_.value for _ in match.tokens])) part = dict_symp['основной диагноз'] if len(lst) == 0: parser = Parser(DIAGNOZ_RULE) for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) match = lst[0][0][1] last = match+text[match:].find(' \n \n') if last == match-1: last = len(text)-1 dict_symp['основной диагноз'] = text[match+1:last] part = text[text.find('Диагноз'):] TYPE = morph_pipeline(['левая', 'слева']) parser = Parser(TYPE) left_rozha = [] lst = [] rozha_types = [['волосистая часть головы', 'волостистой части головы'], ['лицо', "ушная раковина"], ['нос','губы'],['верняя часть туловища', 'верхняя конечность'],['нижняя часть туловища'], ['пах', 'половые органы'],['верняя часть спины'],['нижняя часть спины'], ['плечо'],['предплечье'],['кисть'],['бедро'],['голень'],['стопа'],['голеностоп']] for match in parser.findall(part): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: for i in range(len(rozha_types)): rozha_lst = [] TYPE = morph_pipeline(rozha_types[i]) parser = Parser(TYPE) for match in parser.findall(part): rozha_lst.append(' '.join([_.value for _ in match.tokens])) if len(rozha_lst)>0: left_rozha.append(i+1) dict_symp['ЛПТ'] = left_rozha TYPE = morph_pipeline(['правая', 'справа']) parser = Parser(TYPE) right_rozha = [] lst = [] for match in parser.findall(part): lst.append((match.span, [_.value for _ in match.tokens])) if len(lst)>0: for i in range(len(rozha_types)): rozha_lst = [] TYPE = morph_pipeline(rozha_types[i]) parser = Parser(TYPE) for match in parser.findall(part): rozha_lst.append(' '.join([_.value for _ in match.tokens])) if len(rozha_lst)>0: right_rozha.append(i+1) dict_symp['ППТ'] = right_rozha return dict_symp
from yargy import rule, and_, or_, not_ from yargy.predicates import eq, type as _type, normalized, custom from yargy.pipelines import morph_pipeline from yargy.interpretation import fact CityFact = fact('city', ['prefix', 'title']) CityTitle = morph_pipeline({ 'липецк', 'сургут', 'нальчик', 'москва', 'санкт-петербург', 'питер', 'нижний новгород', 'видное' }).interpretation(CityFact.title.normalized()) CityRule = rule( normalized('город').optional().interpretation(CityFact.prefix), CityTitle, eq(';').optional()).interpretation(CityFact)
BUILDING_TYPE = dictionary({'дом', 'шоссе', 'проспект', 'улица'}).interpretation(Building.buildingType) VALUE = rule(INT, LETTER.optional()) SEP = in_(r'/\-') BUILDING_VALUE = or_(rule(VALUE, LETTER), rule(VALUE)).interpretation(Building.buildingName) STREET_VALUE = dictionary({ 'комсомольский', 'катукова', 'доватора', 'бехтеева', 'артема', 'алтуфьевское', 'миттова', 'школьная', 'рабочая', 'юнтоловский', 'школьная', 'меркулова' }) COMPLEX_STREET = morph_pipeline(['юрия гагарина']) COMPLEX = morph_pipeline([ 'санкт-петербург', 'нижний новгород', 'н.новгород', 'ростов-на-дону', 'набережные челны', 'улан-удэ', 'нижний тагил', 'комсомольск-на-амуре', 'йошкар-ола', 'старый оскол', 'великий новгород', 'южно-сахалинск', 'петропавловск-камчатский',
# Top 200 Russia cities, cover 75% of population COMPLEX = morph_pipeline([ 'санкт-петербург', 'нижний новгород', 'н.новгород', 'ростов-на-дону', 'набережные челны', 'улан-удэ', 'нижний тагил', 'комсомольск-на-амуре', 'йошкар-ола', 'старый оскол', 'великий новгород', 'южно-сахалинск', 'петропавловск-камчатский', 'каменск-уральский', 'орехово-зуево', 'сергиев посад', 'новый уренгой', 'ленинск-кузнецкий', 'великие луки', 'каменск-шахтинский', 'усть-илимск', 'усолье-сибирский', 'кирово-чепецк', ]) SIMPLE = dictionary({ 'москва',
def extract(text): with open(os.path.join(os.getcwd(), 'list_diseases\\diseases'), encoding='UTF-8') as f: diseases = f.read().split('\n') text = text.replace('\ufeff', '') text = text.replace('\n', ' \n ') text = text.replace('\\', ' ') symptoms = ['Дата рождения', 'Дата осмотра','Дата заболевания', 'Возраст', 'Болен дней','Болен часов','Возраст в днях','Время поступления', 'Время заболевания', 'рост','вес', 'IMT', 'давление диаст', 'давление сист', 'температура поступления','мах температура', 'Т-Ан01', 'Т-Ан03', 'пол', 'др заболевания в анамнезе', 'кем направлен', 'побочное действие лекартсв','аллергическая реакция', 'озноб', 'слабость', 'вялость','головная боль', 'нарушение сна', 'нарушение аппетита', 'ломота','тошнота', 'нарушение сознания', 'Судороги', 'Парестезии', 'эритема', 'с четкими границами', 'валик', 'боль','Гиперемия', 'Отек', 'Лимфаденит', 'Лимфангит', 'квартира, дом','контакт с зараженными','речная рыба','провоцирущие факторы', 'предрасполагающие факторы','кол-во сопут заболеваний','соц категория','сопутствующий диагноз','основной диагноз', 'контакт с зараженными', 'пищевой анамнез', 'раневые ворота', 'аллергия на лекарства', 'клещ', 'географический анамнез', 'вредные привычки', 'домашние животные', 'условия труда','избыточное питание', 'ППТ', 'ЛПТ', 'бытовые условия', 'питание', 'интоксикация', 'ЧСС', 'болезненность лимфоузлов', 'увеличенность лимфоузлов','размер лимфоузлов', 'острое начало'] dict_symp = dict.fromkeys(symptoms) dict_index = dict.fromkeys(symptoms) dates_lst = [] dates_spans = [] # Rule for dates detecting DAY = and_(gte(1),lte(31)) MONTH = and_(gte(1),lte(12)) YEAR = and_(gte(1),lte(19)) YEARFULL = and_(gte(1900),lte(2020)) DATE = or_( rule(YEAR,'.',MONTH,'.',DAY), rule(DAY,'.',MONTH,'.',YEAR), rule(DAY,'.',MONTH,'.',YEARFULL), rule(DAY,'.',MONTH), rule(DAY,'.',MONTH,YEARFULL), rule(DAY,'.',MONTH,YEAR)) parser = Parser(DATE) for match in parser.findall(text): dates_lst.append(''.join([_.value for _ in match.tokens])) dates_spans.append(match.span) # Sometimes we dont have information about birthday and we should check difference between years # in first two dates to determine there is information about birthday or not if int(dates_lst[1][-2:])-int(dates_lst[0][-2:])<0: # According medical cards dates have this order dict_symp['Дата рождения'] = dates_lst[0] dict_symp['Дата осмотра'] = dates_lst[1] dict_symp['Дата заболевания'] = dates_lst[2] dict_index['Дата рождения'] = dates_spans[0] dict_index['Дата осмотра'] = dates_spans[1] dict_index['Дата заболевания'] = dates_spans[2] else: birth = None dict_symp['Дата осмотра'] = dates_lst[0] dict_symp['Дата заболевания'] = dates_lst[1] dict_index['Дата осмотра'] = dates_spans[0] dict_index['Дата заболевания'] = dates_spans[1] # If date was written without year, we take year from previous date if len(dict_symp['Дата заболевания'])==5: dict_symp['Дата заболевания'] += dict_symp['Дата осмотра'][dict_symp['Дата осмотра'].rfind('.'):] # Rule for detecring dates with such situation "болен 5 дней" DAY_RULE = morph_pipeline(['дней']) parser = Parser(DAY_RULE) day_lst = [] for match in parser.findall(text): day_lst.append((match.span, [_.value for _ in match.tokens])) if day_lst and dict_symp['Дата заболевания'] is None: dict_symp['Дата заболевания'] = text[day_lst[0][0][0]-20:day_lst[0][0][0]+20] dict_symp['Дата заболевания'] = re.findall(r'\d+', dict_symp['Дата заболевания'])[0] dict_symp['Дата заболевания'] = str(int(dict_symp['Дата осмотра'][:2])-int(dict_symp['Дата заболевания'])) dict_symp['Дата заболевания'] = dict_symp['Дата заболевания']+dict_symp['Дата осмотра'][2:] dict_index['Дата заболевания'] = day_lst[0][0] # Rule for detecting Age age_lst = [] age_spans = [] AGE = and_(gte(0),lte(100)) AGE_RULE = or_(rule("(",AGE,")"), rule(gram('ADJF'),",",AGE)) parser = Parser(AGE_RULE) for match in parser.findall(text): s = ''.join([_.value for _ in match.tokens]) age_lst.append((re.findall(r'\d+', s)[0])) age_spans.append(match.span) if age_lst: dict_symp['Возраст'] = int(age_lst[-1]) dict_index['Возраст'] = age_spans[-1] # Transform dates to datetime format to make calculations try: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%Y') except: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%y') d1 = d1.strftime('%d.%m.%Y') d1 = datetime.strptime(d1, '%d.%m.%Y') try: d2 = datetime.strptime(dict_symp['Дата заболевания'], '%d.%m.%Y') except: d2 = datetime.strptime(dict_symp['Дата заболевания'], '%d.%m.%y') d2 = d2.strftime('%d.%m.%Y') d2 = datetime.strptime(d2, '%d.%m.%Y') dict_symp['Болен дней'] = (d1 - d2).days dict_symp['Болен часов'] = (int(dict_symp['Болен дней'])-1)*24 if dict_symp['Дата рождения'] is None: dict_symp['Возраст в днях'] = int(dict_symp['Возраст'])*365 else: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%Y') d2 = datetime.strptime(dict_symp['Дата рождения'], '%d.%m.%Y') dict_symp['Возраст в днях'] = (d1 - d2).days #Rule for time detecting time_lst = [] time_spans = [] HOURS = and_(gte(0),lte(24)) MINUTES = and_(gte(0),lte(59)) TIME = or_(rule(HOURS,':',MINUTES), rule(HOURS, normalized('час')),) parser = Parser(TIME) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) time_spans.append(match.span) s = s.replace('часов', ':00') s = s.replace('час', ':00') time_lst.append(s) # if we have only 1 date 'Время поступления' = 'Время заболевания' if time_lst: dict_symp['Время поступления'] = time_lst[0] dict_symp['Время заболевания'] = time_lst[0] dict_index['Время поступления'] = time_spans[0] dict_index['Время заболевания'] = time_spans[0] if len(time_lst)>1: dict_symp['Время заболевания'] = time_lst[1] dict_index['Время заболевания'] = time_spans[1] t1 = dict_symp['Время поступления'] t2 = dict_symp['Время заболевания'] delta = int(t1[:t1.find(':')])+24-int(t2[:t2.find(':')]) dict_symp['Болен часов'] = dict_symp['Болен часов'] + delta # Rules for detecting Weight, Height and IMT HEIGHT = and_(gte(50),lte(250)) WEIGHT = and_(gte(10),lte(150)) HEIGHT_RULE = or_(rule(normalized('рост'),'-',HEIGHT), rule(normalized('рост'),'–',HEIGHT), rule(normalized('рост'),':',HEIGHT), rule(normalized('рост'),HEIGHT)) WEIGHT_RULE = or_(rule(normalized('вес'),'-',WEIGHT), rule(normalized('вес'),'–',WEIGHT), rule(normalized('вес'),':',WEIGHT), rule(normalized('вес'),WEIGHT)) height = None parser = Parser(HEIGHT_RULE) for match in parser.findall(text): height = (''.join([_.value for _ in match.tokens])) height_spans = match.span height = re.findall(r'\d+', height)[0] if height: dict_symp['рост'] = int(height) dict_index['рост'] = height_spans weight = None parser = Parser(WEIGHT_RULE) for match in parser.findall(text): weight = (''.join([_.value for _ in match.tokens])) weight = re.findall(r'\d+', weight)[0] weight_spans = match.span if weight: dict_symp['вес'] = int(weight) dict_index['вес'] = weight_spans if (dict_symp['рост'] is not None) and (dict_symp['вес'] is not None): dict_symp['IMT'] = round(dict_symp['вес']/(dict_symp['рост']/100*dict_symp['рост']/100),2) # Rules for detecting pressure ADSIST = and_(gte(50),lte(250)) ADDIAST = and_(gte(20),lte(200)) PRES_RULE = or_(rule('АД', ADSIST,'/',ADDIAST), rule('АД', ADSIST,ADDIAST), rule('АД', ADSIST, ':',ADDIAST), rule('АД','-', ADSIST, '/',ADDIAST), rule('А/Д', ADSIST, '/',ADDIAST), rule('А/Д', ADSIST, ADDIAST), rule('А/Д',' ', ADSIST, '/',ADDIAST), rule(ADSIST, '/',ADDIAST)) pres = None parser = Parser(PRES_RULE) for match in parser.findall(text): pres = (''.join([_.value for _ in match.tokens])) pres = re.findall(r'\d+', pres) pres_spans = match.span if pres: dict_symp['давление сист'] = int(pres[0]) dict_symp['давление диаст'] = int(pres[1]) dict_index['давление сист'] = pres_spans dict_index['давление диаст'] = pres_spans # Rule for detecting Pulse PULSE = and_(gte(40),lte(150)) PULSE_RULE = or_(rule('ЧСС','-',PULSE), rule('ЧСС',PULSE), rule('ЧСС','-',PULSE), rule('ЧСС','/',PULSE), rule('пульс',PULSE),) pulse = None parser = Parser(PULSE_RULE) for match in parser.findall(text): pulse = (''.join([_.value for _ in match.tokens])) pulse = re.findall(r'\d+', pulse) pulse_spans = match.span if pulse: dict_symp['ЧСС'] = int(pulse[0]) dict_index['ЧСС'] = pulse_spans #Rules for detecting temperatures DEGREES = and_(gte(34),lte(42)) SUBDEGREES = and_(gte(0),lte(9)) TEMP_RULE = or_(rule(DEGREES,',',SUBDEGREES), rule(DEGREES,'.',SUBDEGREES), rule(DEGREES)) # Find 'Объективный статус', because this pert contains information about 'температура поступления' status = text[text.find('Объективный статус'): text.find('Объективный статус')+text[text.find('Объективный статус')+1:].find(' \n \n')] temp_lst = [] temp_spans = [] parser = Parser(TEMP_RULE) for match in parser.findall(status): temp_lst.append(''.join([_.value for _ in match.tokens])) temp_spans.append(match.span) if temp_lst: dict_symp['температура поступления'] = temp_lst[0] dict_index['температура поступления'] = temp_spans[0] # Find temperatures in whole text temp_text = text[text.find('Жалобы'):] temp_lst = [] temp_spans = [] parser = Parser(TEMP_RULE) for match in parser.findall(temp_text): temp_lst.append(''.join([_.value for _ in match.tokens])) temp_spans.append(match.span) if temp_lst: if dict_symp['температура поступления'] is None: dict_symp['температура поступления'] = temp_lst[0] dict_index['температура поступления'] = temp_spans[0] dict_symp['мах температура'] = max([float(i.replace(',','.')) for i in temp_lst]) if dict_symp['мах температура']>=38: dict_symp['Т-Ан01'] = 1 else: dict_symp['Т-Ан01'] = 0 if dict_symp['мах температура']>=40: dict_symp['Т-Ан03'] = 3 elif dict_symp['мах температура']>=39: dict_symp['Т-Ан03'] = 2 elif dict_symp['мах температура']>=38: dict_symp['Т-Ан03'] = 1 else: dict_symp['Т-Ан03'] = 0 # Rule for detecting Sex sex_lst = [] sex_spans = [] SEX_RULE = or_(rule(normalized('женский')), rule(normalized('мужской'))) parser = Parser(SEX_RULE) for match in parser.findall(text): sex_lst.append(''.join([_.value for _ in match.tokens])) sex_spans.append(match.span) if sex_lst: dict_symp['пол'] = sex_lst[0] dict_index['пол'] = sex_spans[0] dict_symp['пол'] = dict_symp['пол'].lower().replace('женский', '2') dict_symp['пол'] = dict_symp['пол'].lower().replace('мужской', '1') dict_symp['пол'] = int(dict_symp['пол']) # Rule for detecting DISEASES DISEASES_RULE = morph_pipeline(diseases[:-1]) # anamnez contains information about diseases of patient, but family anamnez contains # information about diseases of patient, and we should remove this part anamnez = text[text.find('Анамнез'): text.find('Анамнез')+text[text.find('Анамнез')+1:].rfind('Анамнез')] family = anamnez[anamnez.find('Семейный'):anamnez.find('Семейный')+60] if family: anamnez = anamnez.replace(family,' ') anamnez = anamnez[:anamnez.rfind('Диагноз')] dis_lst = [] dis_spans = [] parser = Parser(DISEASES_RULE) for match in parser.findall(anamnez): dis_lst.append(' '.join([_.value for _ in match.tokens])) dis_spans.append(match.span) # Special rule for описторхоз OP_RULE = or_(rule(normalized('описторхоз'), not_(normalized('не')))) parser = Parser(OP_RULE) op_lst = [] for match in parser.findall(anamnez):#text op_lst.append((match.span, [_.value for _ in match.tokens])) if op_lst: dis_lst.append(' описторхоз') dis_spans.append(match.span) # Special rule for туберкулез TUB_RULE = rule(normalized('туберкулез'), not_(normalized('отрицает'))) parser = Parser(TUB_RULE) tub_lst = [] for match in parser.findall(anamnez):#text tub_lst.append((match.span, [_.value for _ in match.tokens])) if tub_lst: dis_lst.append(' туберкулез') dis_spans.append(match.span) # Special rule for ВИЧ VICH_RULE = morph_pipeline(['ВИЧ']) parser = Parser(VICH_RULE) vich_lst = [] for match in parser.findall(anamnez):#text vich_lst.append((match.span, [_.value for _ in match.tokens])) if vich_lst: text_vich = text[match.span[1]-30:match.span[1]+30] TYPE = morph_pipeline(['отрицает']) parser = Parser(TYPE) vich_lst = [] for match in parser.findall(text_vich): vich_lst.append((match.span, [_.value for _ in match.tokens])) if not vich_lst: dis_lst.append(' ВИЧ') dis_spans.append(match.span) if dis_lst: dis_lst = list(set(dis_lst)) dict_symp['др заболевания в анамнезе'] = ', '.join(dis_lst) dict_index['др заболевания в анамнезе'] = dis_spans dict_symp['др заболевания в анамнезе'] = morph.parse(dict_symp['др заболевания в анамнезе'])[0].normal_form # Rules for detecting information about л/у LU_RULE = morph_pipeline(['лимфатические узлы', "лимфоузлы", "лу", "л/у"]) parser = Parser(LU_RULE) lu_lst = [] lu_spans = [] for match in parser.findall(text): lu_lst.append((match.span, [_.value for _ in match.tokens])) if lu_lst: dict_symp['Лимфаденит'] = 0 dict_index['Лимфаденит'] = lu_spans text_lu = text[match.span[1]-70:match.span[1]+70] TYPE = morph_pipeline(["болезненны", "болезненные", "болезнены"]) parser = Parser(TYPE) lu_lst = [] for match in parser.findall(text_lu): lu_lst.append((match.span, [_.value for _ in match.tokens])) if lu_lst: dict_symp['болезненность лимфоузлов'] = 1 dict_index['болезненность лимфоузлов'] = match.span dict_symp['Лимфаденит'] = 1 else: dict_symp['болезненность лимфоузлов'] = 0 TYPE = morph_pipeline(['Увеличены', 'увеличенные']) parser = Parser(TYPE) lu_lst = [] for match in parser.findall(text_lu): lu_lst.append((match.span, [_.value for _ in match.tokens])) if lu_lst: dict_symp['увеличенность лимфоузлов'] = 1 dict_index['увеличенность лимфоузлов'] = match.span dict_symp['Лимфаденит'] = 1 else: dict_symp['увеличенность лимфоузлов'] = 0 number = and_(gte(0),lte(9)) LU_SIZE_RULE = or_(rule(number,'.',number), rule(number,',',number)) lu_lst = [] lu_spans = [] parser = Parser(LU_SIZE_RULE) for match in parser.findall(text_lu): lu_lst.append(''.join([_.value for _ in match.tokens])) lu_spans.append(match.span) if lu_lst: dict_symp['размер лимфоузлов'] = lu_lst[0] dict_index['размер лимфоузлов'] = lu_spans[0] # Rule for 'кем направлен' NAPR_RULE = morph_pipeline(['Поликлиника',"скорая помощь", "ск/помощь", 'СМП', "обратился"]) napr = None napr_lst = [] napr_spans = [] parser = Parser(NAPR_RULE) for match in parser.findall(text): napr_lst.append(' '.join([_.value for _ in match.tokens])) napr_spans.append(match.span) if napr_lst: dict_index['кем направлен'] = napr_spans[0] napr = napr_lst[-1] napr = morph.parse(napr)[0].normal_form if napr == "обратиться": dict_symp['кем направлен'] = 3 elif napr == "скорая помощь" or napr == "ск/помощь" or napr == 'смп'or napr == "ск / помощь" or napr == "скорой помощь" or napr == "скорую помощь": dict_symp['кем направлен'] = 1 elif napr == "поликлиника": dict_symp['кем направлен'] = 2 # Rule for allergy ALLERG_RULE = or_(rule(normalized('Аллергическая'),normalized('реакция'), normalized('на')), rule(normalized('не'),normalized('переносит'))) all_lst = [] parser = Parser(ALLERG_RULE) for match in parser.findall(text): all_lst.append((match.span, [_.value for _ in match.tokens])) if all_lst: index = all_lst[0][0][1] dict_symp['аллергическая реакция'] = text[index:text[index:].find('.')+index] dict_index['аллергическая реакция'] = [all_lst[0][0][0], text[index:].find('.')+index] # Rules for different symptoms symptoms = [['озноб', 'познабливание'], 'слабость', ['вялость', 'разбитость'],'головная боль', 'нарушение сна', 'нарушение аппетита', 'ломота','тошнота', 'нарушение сознания','Судороги', 'Парестезии', ['эритема', 'эритематозная', 'эритематозно'], ['с четкими границами', 'границами четкими', 'четкими неровными краями', 'с четкими краями', 'краями четкими' , 'четкими неровными краями', 'четкими контурами', 'языков пламени'], ['валик', 'вал'], 'боль',['Гиперемия', 'гиперемирована'], 'Отек', 'Лимфангит', ['рана', "раневые ворота", "входные ворота"],['клещ', "присасывание"], 'интоксикация', 'острое начало'] for i in symptoms: sym_lst = [] sym_spans = [] if isinstance(i, str): SYM_RULE = morph_pipeline([i]) parser = Parser(SYM_RULE) for match in parser.findall(text): sym_lst.append(' '.join([_.value for _ in match.tokens])) sym_spans.append(match.span) if sym_lst: dict_symp[i] = 1 dict_index[i] = sym_spans[0] else: dict_symp[i] = 0 else: SYM_RULE = morph_pipeline(i) parser = Parser(SYM_RULE) for match in parser.findall(text): sym_lst.append(' '.join([_.value for _ in match.tokens])) sym_spans.append(match.span) if sym_lst: dict_symp[i[0]] = 1 dict_index[i[0]] = sym_spans[0] else: dict_symp[i[0]] = 0 #This fuction used for features which have the same rule def find_feature(feature, RULE, RULE2, space=[40,40]): parser = Parser(RULE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if lst: dict_index[feature] = match.span add_text = text[match.span[1]-space[0]:match.span[1]+space[1]] parser = Parser(RULE2) lst = [] for match in parser.findall(add_text): lst.append((match.span, [_.value for _ in match.tokens])) if lst: dict_symp[feature] = 1 dict_index[feature] = match.span else: dict_symp[feature] = 0 GEO_RULE = morph_pipeline(['географический', 'выезжал']) GEO_RULE2 = rule(not_(normalized('не')),normalized('выезжал')) geo_space = [40,40] COND_RULE = morph_pipeline(['бытовые']) COND_RULE2 = rule(not_(normalized('не')),normalized('удовлетворительные')) cond_space = [0,60] SEC_COND_RULE = morph_pipeline(['Социально-бытовые']) sec_cond_space = [0,60] WORK_COND_RULE = morph_pipeline(['условия труда']) work_cond_space = [20,20] CONTACT_RULE = morph_pipeline(['контакт']) CONTACT_RULE2 = morph_pipeline(['да']) contact_space = [0,40] WATER_RULE = morph_pipeline(['сырой воды']) WATER_RULE2 = morph_pipeline(['не было', 'отрицает', 'нет']) water_space = [80,80] features = ['географический анамнез', 'бытовые условия', 'бытовые условия', 'условия труда','контакт с зараженными','пищевой анамнез'] rules = [GEO_RULE, COND_RULE, SEC_COND_RULE, WORK_COND_RULE, CONTACT_RULE, WATER_RULE] sec_rules = [GEO_RULE2, COND_RULE2, COND_RULE2, COND_RULE2, CONTACT_RULE2, WATER_RULE2] spaces = [geo_space, cond_space, sec_cond_space, work_cond_space, contact_space, water_space] for i in range(len(features)): find_feature(features[i],rules[i],sec_rules[i],spaces[i]) # Rules for bad habbits HAB_RULE = morph_pipeline(['вредные привычки', 'алкоголь']) parser = Parser(HAB_RULE) hab_lst = [] for match in parser.findall(text): hab_lst.append((match.span, [_.value for _ in match.tokens])) if hab_lst: dict_index['вредные привычки'] = match.span text_hab = text[match.span[1]-80:match.span[1]+80] HAB_RULE = morph_pipeline(['не было', 'отрицает', 'нет', 'не употребляет']) parser = Parser(HAB_RULE) hab_lst = [] for match in parser.findall(text_hab): hab_lst.append((match.span, [_.value for _ in match.tokens])) if hab_lst: dict_symp['вредные привычки'] = 0 dict_index['вредные привычки'] = match.span else: dict_symp['вредные привычки'] = 1 SMOKE_RULE = or_(rule(not_(normalized('не')),normalized('курит')), rule(not_(normalized('не')),normalized('употребляет'))) parser = Parser(SMOKE_RULE) hab_lst = [] for match in parser.findall(text): hab_lst.append((match.span, [_.value for _ in match.tokens])) if hab_lst: dict_symp['вредные привычки'] = 1 dict_index['вредные привычки'] = match.span # Rules for work work_lst = [] WORK_RULE = morph_pipeline(['работает']) parser = Parser(WORK_RULE) for match in parser.findall(text): work_lst.append((match.span, [_.value for _ in match.tokens])) if work_lst: dict_symp['соц категория'] = 0 dict_index['соц категория'] = match.span WORK_RULE = rule(not_(normalized('не')),normalized('работает')) parser = Parser(WORK_RULE) work_lst = [] for match in parser.findall(text): work_lst.append((match.span, [_.value for _ in match.tokens])) if work_lst: dict_symp['соц категория'] = 1 dict_index['соц категория'] = match.span # If patient has условия труда probably he has a job if dict_symp['условия труда'] is not None: dict_symp['соц категория'] = 1 # Rule for food FOOD_RULE = morph_pipeline(['питание']) parser = Parser(FOOD_RULE) food_lst = [] for match in parser.findall(text): food_lst.append((match.span, [_.value for _ in match.tokens])) if food_lst: dict_index['избыточное питание'] = match.span text_food = text[match.span[1]-20:match.span[1]+20] FOOD_RULE = or_(rule(not_(normalized('не')),normalized('удовлетворительное')), rule(not_(normalized('не')),normalized('полноценное'))) parser = Parser(FOOD_RULE) food_lst = [] for match in parser.findall(text_food): food_lst.append((match.span, [_.value for _ in match.tokens])) if food_lst: dict_symp['питание'] = 1 dict_index['питание'] = match.span else: dict_symp['питание'] = 0 FOOD_RULE = rule(not_(normalized('не')),normalized('избыточное')) parser = Parser(FOOD_RULE) food_lst = [] for match in parser.findall(text_food): food_lst.append((match.span, [_.value for _ in match.tokens])) if food_lst: dict_index['избыточное питание'] = match.span dict_symp['избыточное питание'] = 1 else: dict_symp['избыточное питание'] = 0 # Rule for fish FISH_RULE = morph_pipeline(['рыба']) parser = Parser(FISH_RULE) fish_lst = [] for match in parser.findall(text): fish_lst.append((match.span, [_.value for _ in match.tokens])) if fish_lst: dict_index['речная рыба'] = match.span text_fish = text[match.span[1]-40:match.span[1]+40] FISH_RULE = morph_pipeline(['да', 'постоянно']) parser = Parser(FISH_RULE) fish_lst = [] for match in parser.findall(text_fish): fish_lst.append((match.span, [_.value for _ in match.tokens])) if fish_lst: dict_symp['речная рыба'] = 1 FISH_RULE = rule(not_(normalized('не')),normalized('употребляет')) parser = Parser(FISH_RULE) fish_lst = [] for match in parser.findall(text_fish): fish_lst.append((match.span, [_.value for _ in match.tokens])) if fish_lst: dict_symp['речная рыба'] = 0 dict_index['речная рыба'] = match.span # Rule for home home = None home_span = None home_types = [['бездомный'], ['дом благоустроенный', 'частный дом'], ['дом не благоустроенный','дом неблагоустроенный'], ['квартира не благоустроенная', 'квартира неблагоустроенная'], ['квартира благоустроенная', 'благоустроенная квартира'],] for i in range(len(home_types)): home_lst = [] HOME_RULE = morph_pipeline(home_types[i]) parser = Parser(HOME_RULE) for match in parser.findall(text): home_lst.append((match.span, [_.value for _ in match.tokens])) if home_lst: home = i home_span = match.span dict_symp['квартира, дом'] = home dict_index['квартира, дом'] = home_span pets = [] pets_span = [] pet_types = [['кошка'], ['собака'], ['корова','коза']] # Rule for pets for i in range(len(pet_types)): pet_lst = [] PET_RULE = morph_pipeline(pet_types[i]) parser = Parser(PET_RULE) for match in parser.findall(text): pet_lst.append(' '.join([_.value for _ in match.tokens])) pets_span.append(match.span) if pet_lst: pets.append(i+1) if len(pets)>1: pets = 4 elif pets: pets = pets[0] else: pets = 0 dict_symp['домашние животные'] = pets dict_index['домашние животные'] = pets_span # Rules for different factors factors = [] factors_span = [] factor_types = [['ссадины',"царапины", "раны", "расчесы", "уколы", "потертости", "трещины", 'вскрытие'], ['ушибы'], ['переохлаждение','перегревание','смена температуры'], ['инсоляция'], ['стресс'], ['переутомление']] def find_factors(factor_types): for i in range(len(factor_types)): factor_lst = [] FACT_RULE = morph_pipeline(factor_types[i]) parser = Parser(FACT_RULE) for match in parser.findall(text): factor_lst.append(' '.join([_.value for _ in match.tokens])) factors_span.append(match.span) if factor_lst: factors.append(i+1) find_factors(factor_types) if factors: dict_symp['провоцирущие факторы'] = factors dict_index['провоцирущие факторы'] = factors_span factors = [] factors_span = [] factor_types = [['микоз',"диабет", "ожирение", "варикоз", "недостаточность", "лимфостаз", "экзема"], ['тонзилит',"отит", "синусит", "кариес", "пародонтоз", "остеомиелит", "тромбофлебит", "трофические язвы"], ['резиновая обувь','загрязнения кожных'], ['соматические заболевания']] find_factors(factor_types) if factors: dict_symp['предрасполагающие факторы'] = factors dict_index['предрасполагающие факторы'] = factors_span # Rule for detecting the second diagnosis DIAGNOZ_RULE = or_(rule(normalized('сопутствующий'), not_(or_(gram('NOUN')))), rule(normalized('сопутствующий'),normalized('диагноз')), rule(normalized('диагноз'),normalized('сопутствующий')),) parser = Parser(DIAGNOZ_RULE) diag_lst = [] for match in parser.findall(text): diag_lst.append((match.span, [_.value for _ in match.tokens])) if diag_lst: dict_symp['сопутствующий диагноз'] = text[match.span[1]+2:match.span[1]+text[match.span[1]:].find(' \n \n')] dict_index['сопутствующий диагноз'] = [match.span[1]+2,match.span[1]+text[match.span[1]:].find(' \n \n')] dict_symp['кол-во сопут заболеваний'] = dict_symp['сопутствующий диагноз'].count('\n') if dict_symp['кол-во сопут заболеваний']==0: dict_symp['кол-во сопут заболеваний']=1 # Rule for detecting the first diagnosis DIAGNOZ_RULE = or_(rule(normalized('диагноз'),normalized('при'),normalized('поступлении')), rule(normalized('клинический'),normalized('диагноз')), rule(normalized('диагноз'),normalized('клинический')), rule(normalized('основной'),normalized('диагноз')), rule(normalized('диагноз'),normalized('основной')), rule(normalized('Ds')), rule(normalized('Ds:')), rule(not_(or_(gram('ADJF'),gram('NOUN'))),normalized('диагноз'),not_(or_(gram('ADJF'),gram('PREP'))))) diag_lst = [] parser = Parser(DIAGNOZ_RULE) for match in parser.findall(text): diag_lst.append((match.span, [_.value for _ in match.tokens])) last = match.span[1]+text[match.span[1]:].find(' \n \n') if last == match.span[1]-1: last = len(text)-1 dict_symp['основной диагноз'] = text[match.span[1]+1:last] dict_index['основной диагноз'] = [match.span[1]+1,last] # Rules for detecting ЛПТ and ППТ LEFT_RULE = morph_pipeline(['левая', 'слева']) parser = Parser(LEFT_RULE) side_lst = [] for match in parser.findall(dict_symp['основной диагноз']): side_lst.append((match.span, [_.value for _ in match.tokens])) RIGHT_RULE = morph_pipeline(['правая', 'справа']) parser = Parser(RIGHT_RULE) for match in parser.findall(dict_symp['основной диагноз']): side_lst.append((match.span, [_.value for _ in match.tokens])) # If we dont have information about side in 'основной диагноз', check other diagnosis DIAGNOZ_RULE = or_(rule(normalized('Обоснование'),normalized('Диагноза'))) part = dict_symp['основной диагноз'] if len(side_lst) == 0: part = text[text.find('Диагноз'):] side_lst = [] parser = Parser(DIAGNOZ_RULE) for match in parser.findall(part): side_lst.append((match.span, [_.value for _ in match.tokens])) last = match.span[1]+part[match.span[1]:].find(' \n \n') if last == match.span[1]-1: last = len(part)-1 explaining = part[match.span[1]+1:last] if len(explaining)>1: part = part.replace(explaining,' ') # If we dont have information about side in diagnosis, check other 'Жалобы' DIAGNOZ_RULE = or_(rule(normalized('Жалобы'))) comp_lst = [] parser = Parser(DIAGNOZ_RULE) for match in parser.findall(text): comp_lst.append((match.span, [_.value for _ in match.tokens])) last = comp_lst[0][0][1]+text[comp_lst[0][0][1]:].find(' \n \n') if last == comp_lst[0][0][1]-1: last = len(text)-1 zhalobi = text[comp_lst[0][0][1]+1:last] rozha_types = [['волосистая часть головы', 'волостистой части головы'], ['лицо','щека','лоб','глаз'], ['нос','губы'],['верняя часть туловища', 'верхняя конечность'],['нижняя часть туловища'], ['пах', 'половые органы'],['верняя часть спины'],['нижняя часть спины'], ['плечо'],['предплечье'],['кисть'],['бедро'],['голень'],['стопа'],['голеностоп'], ["ушная раковина"]] def find_side(parser, sidetext): rozha = [] lst = [] for match in parser.findall(sidetext): lst.append((match.span, [_.value for _ in match.tokens])) if lst: for i in range(len(rozha_types)): rozha_lst = [] TYPE = morph_pipeline(rozha_types[i]) parser = Parser(TYPE) for match in parser.findall(sidetext):#part): rozha_lst.append(' '.join([_.value for _ in match.tokens])) if rozha_lst: if i ==15: rozha.append('2.1') else: rozha.append(i+1) return(rozha) parser = Parser(LEFT_RULE) dict_symp['ЛПТ'] = find_side(parser, part) parser = Parser(RIGHT_RULE) dict_symp['ППТ'] = find_side(parser, part) if not dict_symp['ППТ'] and not dict_symp['ЛПТ']: parser = Parser(LEFT_RULE) dict_symp['ЛПТ'] = find_side(parser, zhalobi) parser = Parser(RIGHT_RULE) dict_symp['ППТ'] = find_side(parser, zhalobi) # Special rule for detecting face face_lst = [] FACE_RULE = morph_pipeline(['нос','губы']) parser = Parser(FACE_RULE) for match in parser.findall(part): face_lst.append((match.span, [_.value for _ in match.tokens])) if face_lst: dict_symp['ППТ'].append(3) dict_symp['ЛПТ'].append(3) dict_symp['ЛПТ'] = list(set(dict_symp['ЛПТ'])) dict_symp['ППТ'] = list(set(dict_symp['ППТ'])) if not dict_symp['ППТ']: dict_symp['ППТ'] = None if not dict_symp['ЛПТ']: dict_symp['ЛПТ'] = None return dict_symp, dict_index
POSITION = morph_pipeline([ 'святой', 'патриарх', 'митрополит', 'царь', 'король', 'царица', 'император', 'императрица', 'принц', 'принцесса', 'князь', 'граф', 'графиня', 'барон', 'баронесса', 'княгиня', 'президент', 'премьер-министр', 'экс-премьер', 'пресс-секретарь', 'министр', 'замминистр', 'заместитель', 'глава', 'канцлер', 'помощник', 'посол', 'губернатор', 'председатель', 'спикер', 'диктатор', 'лидер', 'генсек', 'премьер', 'депутат', 'вице-премьер', 'сенатор', 'полпред', 'госсекретарь', 'вице-президент', 'сопредседатель', 'зам', 'мэр', 'вице-спикер', 'замруководителя', 'зампред', 'муфтий', 'спецпредставитель', 'руководитель', 'статс-секретарь', 'зампредседатель', 'представитель', 'ставленник', 'мадеро', 'вице-губернатор', 'зампредсовмин', 'наркоминдела', 'генпрокурор', 'комиссар', 'рейхсканцлер', 'советник', 'замглавы', 'секретарь', 'парламентарий', 'замгендиректор', 'вице-председатель', 'постпред', 'госкомтруд', 'предсовмин', 'преемник', 'делегат', 'шеф', 'консул', 'замминистра', 'главкомпис', 'чиновник', 'врио', 'управделами', 'нарком', 'донпродкомиссар', 'председ', 'гендиректор', 'генерал-губернатор', 'обревком', 'правитель', 'замсекретарь', 'главнокомандующий', 'вице-мэр', 'наместник', 'спичрайтер', 'вице-консул', 'мвэс', 'облревком', 'главковерх', 'пресс-атташе', 'торгпред', 'член', 'назначенец', 'эмиссар', 'обрядоначальник', 'главком', 'единоросс', 'политик', 'генерал', 'замгенпрокурор', 'дипломат', 'главноуполномоченный', 'генерал-фельдцейхмейстер', 'комендант', 'казначей', 'уполномоченный', 'обер-прокурор', 'наркомзем', 'соправитель', 'основатель', 'сооснователь', 'управляющий директор', 'управляющий партнер', 'партнер', 'руководитель', 'аналитик', 'зампред', 'миллиардер', 'миллионер', 'автор', 'актер', 'актриса', 'певец', 'певица', 'исполнитель', 'солист', 'режиссер', 'сценарист', 'писатель', 'музыкант', 'композитор', 'корреспондент', 'журналист', 'редактор', 'дирижер', 'кинорежиссер', 'звукорежиссер', 'детектив', 'пианист', 'драматург', 'артист', 'балетмейстер', 'скрипач', 'хореограф', 'танцовщик', 'документалист', 'поэт', 'литератор', 'киноактер', 'вокалист', 'бард', 'комик', 'продюсер', 'кинодраматург', 'киноактриса', 'балерина', 'пианистка', 'критик', 'танцор', 'концертмейстер', 'симфонист', 'сатирик', 'аранжировщик', 'саксофонист', 'юморист', 'шансонье', 'гастролер', 'виолончелист', 'постановщик', 'кинематографист', 'сценограф', 'джазмен', 'музыковед', 'киноартист', 'педагог', 'хормейстер', 'беллетрист', 'примадонна', 'инструменталист', 'альтист', 'шоумен', 'виртуоз', 'пародист', 'декоратор', 'модельер', 'очеркист', 'оперетта', 'контрабасист', 'карикатурист', 'дуэт', 'монтажер', 'живописец', 'скульптор', 'режиссура', 'архитектор', 'антрепренер', 'импрессарио', 'прозаик', 'труппа', 'трагик', 'клоун', 'солистка', 'либреттист', 'литературовед', 'портретист', 'гример', 'художник', 'импровизатор', 'декламаторша', 'телеведущий', 'импресарио', 'мастер', 'аккомпаниатор', 'шахматист', 'иллюзионист', 'эстрадник', 'эстрада', 'спортсмен', 'дизайнер', 'кинокритик', 'публицист', 'чтец', 'конферансье', 'студиец', 'коверный', 'куплетист', 'знаменитость', 'ученый', 'балет', 'искусствовед', 'гитарист', 'доктор', 'академик', 'судья', 'юрист', 'представитель', 'директор', 'прокурор', 'отец', 'мать', 'мама', 'папа', 'брат', 'сестра', 'тёща', 'тесть', 'дедушка', 'бабушка', 'жена', 'муж', 'дочь', 'сын', 'мистер', 'миссис', 'господин', 'госпожа', 'пан', 'пани', 'сэр', 'мисс', 'боксер', 'боец', 'атлет', 'футболист', 'баскетболист', 'агроном', 'президент', 'сопрезидент', 'вице-президент', 'экс-президент', 'председатель', 'руководитель', 'директор', 'глава', ])
def __init__(self, filename, university): self.filename = filename self.university = university self.rpd_task_and_goals = morph_pipeline([ 'цели и задачи', 'цели освоения', 'задачи освоения', 'аннотация', 'краткое содержание', 'краткое описание' ]) self.rpd_education_result = morph_pipeline( ['планируемый результат обучение', 'компетенции']) self.rpd_discipline_link = morph_pipeline( ['место учебный дисциплина', 'место дисциплины']) self.rpd_discipline_structure = caseless_pipeline( ['содержание дисциплины', 'структура дисциплины']) self.rpd_lecture_theme = morph_pipeline(['лекции']) self.rpd_practice_theme = morph_pipeline([ 'практические занятия', 'семинар', 'семинарские занятия', 'лабораторные работы' ]) self.rpd_selfwork_theme = morph_pipeline([ 'самостоятельная работа обучающихся по дисциплине', 'самостоятельная работа студентов', 'домашняя работа' ]) self.rpd_education_zyn = rule(dictionary({'Знать', 'Уметь', 'Владеть'})) self.section_rule = rule( dictionary({"раздел", "тема", "дисциплина", "наименование"})) self.prd_lectures = rule( morph_pipeline([ 'тема лекций', 'содержание занятий', 'содержание лекционного занятия' ])) self.prd_practices = rule( morph_pipeline( ['наименование', 'содержание практического занятия', 'тема'])) self.rpd_srs = rule( morph_pipeline([ 'СРС', 'содержание занятий', 'содержание задания', 'тема СРО', 'тема СРС' ])) self.rpd_name = rule( morph_pipeline([ 'рабочая программа дисциплины', 'дисциплина', 'программа дисциплины' ])) self.table_rpd_name = rule(dictionary({'дисциплина'})) self.rpd_lectures_optional = rule(morph_pipeline(['содержание'])) self.rpd_practices_optional = rule( morph_pipeline(['содержание', 'cодержание практического занятия'])) self.rpd_srs_optional = rule( morph_pipeline(['содержание', 'содержание задания'])) self.documentText = dict() self.docs_headers = list() self.fullText = list() parser_RPD_task_and_goals = Parser(self.rpd_task_and_goals) parser_RPD_education_result = Parser(self.rpd_education_result) parser_RPD_discipline_link = Parser(self.rpd_discipline_link) parser_PRD_discipline_structure = Parser(self.rpd_discipline_structure) parser_PRD_lecture_theme = Parser(self.rpd_lecture_theme) parser_RPD_practice_theme = Parser(self.rpd_practice_theme) parser_RPD_selfwork_theme = Parser(self.rpd_selfwork_theme) parser_PRD_zyn_result = Parser(self.rpd_education_zyn) parser_PRD_themes = Parser(self.section_rule) parser_PRD_lectures = Parser(self.prd_lectures) parser_PRD_practices = Parser(self.prd_practices) parser_RPD_srs = Parser(self.rpd_srs) parser_RPD_name = Parser(self.rpd_name) self.parser_table_RPD_name = Parser(self.table_rpd_name) parser_RPD_lectures_desc = Parser(self.rpd_lectures_optional) parser_RPD_practices_desc = Parser(self.rpd_practices_optional) parser_RPD_srs_desc = Parser(self.rpd_srs_optional) self.get_rpd_text(filename) self.documentText['университет'] = self.university self.documentText['название дисциплины'] = self.get_rpd_name( parser_RPD_name) self.documentText[ 'направление подготовки'] = self.get_direction_of_preparation() self.documentText['цели и задачи'] = "".join( self.find_boundries(parser_RPD_task_and_goals)) self.documentText['результаты обучения'] = self.find_boundries( parser_RPD_education_result) fgos_table = "" flag = True if self.documentText['результаты обучения'] is not None: for item in self.documentText['результаты обучения']: if "Таблица: " in item: fgos_table = item[8:] self.documentText['результаты обучения'] = item if fgos_table == "": fgos_table = self.documentText['результаты обучения'] flag = False self.documentText['ЗУН'] = self.get_zyn_results( fgos_table, parser_PRD_zyn_result, flag) temp = "" for key, value in self.documentText['ЗУН'].items(): temp += key + " " for item in value: temp += "".join(item) + " " self.documentText['ЗУН'] = temp.replace("~", "") self.documentText['компетенции'] = self.search_place_fgos( "".join(fgos_table)) temp = "" for key, value in self.documentText['компетенции'].items(): temp += key + " " + value self.documentText['компетенции'] = temp self.documentText['результаты обучения'] = "".join( self.documentText['результаты обучения']).replace("~", '\t').replace( "@", '\n') self.documentText['связь дисциплины'] = "".join( self.find_boundries(parser_RPD_discipline_link)).replace( "Таблица: ", "").replace("~", "\t").replace("@", "\n") self.documentText['структура дисциплины'] = self.find_boundries( parser_PRD_discipline_structure) discipline_themes_table = "" for item in self.documentText['структура дисциплины']: if "Таблица: " in item: discipline_themes_table = item break self.documentText['структура дисциплины'] = "".join( self.documentText['структура дисциплины']).replace( "Таблица: ", '').replace("~", '\t').replace("@", "\n") self.documentText['темы структуры дисципилны'] = "".join( self.convert_string_to_table(discipline_themes_table[8:], parser_PRD_themes)) self.documentText['лекции'] = self.find_boundries( parser_PRD_lecture_theme) if self.documentText['лекции'] is not None: discipline_lectures_table = "" for item in self.documentText['лекции']: if "Таблица: " in item: discipline_lectures_table = item break self.documentText['темы лекций'] = "".join( self.convert_string_to_table(discipline_lectures_table[8:], parser_PRD_lectures)) self.documentText['описание лекций'] = "".join( self.convert_string_to_table(discipline_lectures_table[8:], parser_RPD_lectures_desc)) self.documentText['лекции'] = "".join( self.documentText['лекции']).replace("Таблица: ", '').replace( "~", '\t').replace("@", '\n') self.documentText['практики'] = self.find_boundries( parser_RPD_practice_theme) if self.documentText['практики'] is not None: discipline_practises_table = "" for item in self.documentText['практики']: if "Таблица: " in item: discipline_practises_table = item break self.documentText['темы практик'] = "".join( self.convert_string_to_table(discipline_practises_table[8:], parser_PRD_practices)) self.documentText['описание практик'] = "" # self.convert_string_to_table(discipline_lectures_table[8:],parser_RPD_practices_desc) self.documentText['практики'] = "".join( self.documentText['практики']).replace( "Таблица: ", '').replace("~", '\t').replace("@", '\n') self.documentText['СРС'] = self.find_boundries( parser_RPD_selfwork_theme) if self.documentText['СРС'] is not None: discipline_srs_table = "" for item in self.documentText['СРС']: if "Таблица: " in item: discipline_srs_table = item break self.documentText['темы СРС'] = "".join( self.convert_string_to_table(discipline_srs_table[8:], parser_RPD_srs)) self.documentText['описание СРС'] = "" # self.convert_string_to_table(discipline_srs_table[8:], parser_RPD_srs_desc) self.documentText['СРС'] = "".join( self.documentText['СРС']).replace("Таблица: ", '').replace( "~", '\t').replace("@", '\n')
from yargy import rule, and_, not_, or_ from yargy.interpretation import fact from yargy.predicates import gram, eq, type, in_ from yargy.relations import gnc_relation from yargy.pipelines import morph_pipeline INT = type('INT') #Слова до номера документа NCONTRWORD = morph_pipeline(['ПЛАТЕЖНОЕ ПОРУЧЕНИЕ №']) Ncontract = fact('Ncontract', ['num']) #Слова до номера документа NCONTRWORD = morph_pipeline(['ПЛАТЕЖНОЕ ПОРУЧЕНИЕ №']) NUM = rule(INT).interpretation(Ncontract.num.custom(int)) #Правило для номера документа NCONTRACT = rule(NCONTRWORD, NUM).interpretation(Ncontract)
from yargy import or_, rule from yargy.interpretation import fact from yargy.pipelines import morph_pipeline from .literal import LIST_OF_LITERALS, LIST_OF_NUMERALS Vestibule = fact('Vestibules', ['num']) VESTIBULE_WORD = morph_pipeline(['вестибюль', 'павильон']) VESTIBULE = rule( or_( # вестибюль 1 и 2 rule( VESTIBULE_WORD, LIST_OF_NUMERALS.means(Vestibule.num).optional(), ), # первый и второй вестибюли rule( LIST_OF_LITERALS.means(Vestibule.num), VESTIBULE_WORD, ), )).means(Vestibule)
from yargy import or_, rule from yargy.interpretation import attribute, fact import yargy.interpretation as meaning from yargy.pipelines import morph_pipeline from yargy.predicates import caseless, gram, normalized from .common import Array # Working = fact('Working', [attribute('to', default=[])]) Type = fact('Type', [attribute('value', default=[]), 'status', attribute('inversed', default=False)]) ENTER_EXIT_WORD = rule( or_(caseless('на'), caseless('для')).optional(), morph_pipeline(['вход', 'выход']).interpretation(Type.value), ).interpretation(Type) # и на вход и на выход ON_ENTER_AND_EXIT = rule( caseless('и').optional(), ENTER_EXIT_WORD .interpretation(meaning.custom(lambda p: p.value)) .interpretation(Array.element), # caution: misses comma, I don't know why rule( caseless('и').optional(), ENTER_EXIT_WORD .interpretation(meaning.custom(lambda p: p.value)) .interpretation(Array.element), ).optional(), ).interpretation(Array)
from yargy import rule, and_, or_, not_ from yargy.predicates import eq, type as _type, normalized, custom from yargy.pipelines import morph_pipeline from yargy.interpretation import fact StreetFact = fact('street', ['prefix', 'title']) StreetPrefix = morph_pipeline([ 'улица', 'проспект', 'шоссе', 'бульвар', 'тракт', 'микрорайон', 'проезд', 'аллеи' ]).interpretation(StreetFact.prefix) StreetTitle = morph_pipeline([ 'комсомольский', 'катукова', 'рабочая', 'доватора', 'бехтеева', 'артема', 'полиграфическая', 'каширское', 'октябрьский', 'миттова', 'алтуфьевское', 'югорская', '30 лет победы', 'горького', 'крылова', 'хамовнический вал', 'парковая', 'пришвина',
UNI_NAMES_GEN = load_lines(os.path.join(FOLDER, 'dicts/VUZY.txt')) UNI_NAMES = set(UNI_NAMES_GEN) SPECIALIZATIONS = load_lines(os.path.join(FOLDER, 'dicts/specs_only.txt')) SPECIALIZATION = caseless_pipeline(SPECIALIZATIONS).interpretation( Education.specialization) """ """ YEAR = and_(gte(1900), lte(2100)).interpretation( Date.year.custom(int)).interpretation(Education.year) UNI_NAME_RULE = rule( or_(rule(or_(eq('Филиал'), eq('филиал')), morph_pipeline(UNI_NAMES)), caseless_pipeline(UNI_NAMES))).interpretation(Education.name) ANON_COURSE_NAME = rule( and_( not_(eq('имени')), not_(eq('.')), ).repeatable(max=5)).interpretation(Education.name) EDU_ELEM = rule(or_(YEAR, UNI_NAME_RULE, SPECIALIZATION)) EDUCATION = rule(YEAR, UNI_NAME_RULE, SPECIALIZATION.optional()).interpretation(Education) EXTRA_EDU_ELEM = rule( or_(YEAR, or_(UNI_NAME_RULE, ANON_COURSE_NAME), SPECIALIZATION))
TYPE = morph_pipeline([ 'АО', 'ОАО', 'ООО', 'ЗАО', 'ПАО', # TODO Check abbrs # 'ик', # 'нк', # 'хк', # 'ип', # 'чп', # 'ичп', # 'гпф', # 'нпф', # 'бф', # 'спао', # 'сро', 'общество', 'акционерное общество', 'открытое акционерное общество', 'общество с ограниченной ответственностью', 'закрытое акционерное общество', 'публичное акционерное общество', 'агентство', 'компания', 'организация', 'издательство', 'газета', 'концерн' 'фирма', 'завод', 'предприятие', 'корпорация', 'группа', 'группа компаний', 'санаторий', 'объединение', 'бюро', 'подразделение', 'филиал', 'представительство', 'фонд', 'центр', 'нии', 'академия', 'академия наук', 'обсерватория', 'университет', 'институт', 'политех', 'колледж', 'техникум', 'училище', 'школа', 'музей', 'библиотека', 'авиакомпания', 'госкомпания', 'инвесткомпания', 'медиакомпания', 'оффшор-компания', 'радиокомпания', 'телекомпания', 'телерадиокомпания', 'траст-компания', 'фактор-компания', 'холдинг-компания', 'энергокомпания', 'компания-производитель', 'компания-изготовитель', 'компания-заказчик', 'компания-исполнитель', 'компания-посредник', 'группа управляющих компаний', 'агрофирма', 'турфирма', 'юрфирма', 'фирма-производитель', 'фирма-изготовитель', 'фирма-заказчик', 'фирма-исполнитель', 'фирма-посредник', 'авиапредприятие', 'агропредприятие', 'госпредприятие', 'нацпредприятие', 'промпредприятие', 'энергопредприятие', 'авиакорпорация', 'госкорпорация', 'профорганизация', 'стартап', 'нотариальная контора', 'букмекерская контора', 'авиазавод', 'автозавод', 'винзавод', 'подстанция', 'гидроэлектростанция', ])
def yargy_parser(path): RULE = fact( 'RULE', ['name', 'tresh', 'num'] ) INT = type('INT') PUNCT = type('PUNCT') DOT = or_(eq('.'), eq(',')) NAME_mtbf = morph_pipeline( [ 'MTTF', 'MTBF', 'mean time between', 'mean time between failures', 'mean time between failure', ] ).interpretation( RULE.name ) NAME_mttr = morph_pipeline( [ 'MTTR', 'mean time to', 'Mean Time To Repair', 'repair time', ] ).interpretation( RULE.name ) NUM_MTBF = or_(rule(INT, DOT, INT), rule(INT), rule(INT, DOT, INT, DOT, INT), rule(INT, INT), rule(INT, INT, INT)) UNIT_mtbf = morph_pipeline( [ 'year', 'years', 'hour', 'hours', 'год', 'час', 'h', 'ч', 'тыс. часов' ] ) UNIT_mttr = morph_pipeline( [ 'hour', 'hours', 'час', 'h', 'ч' ] ) X_mtbf = rule(NUM_MTBF, UNIT_mtbf.optional() ).interpretation( RULE.num ) X_mttr = rule(INT, UNIT_mttr.optional() ).interpretation( RULE.num ) TRESH = rule(and_(not_(eq(NUM_MTBF)), or_(not_(eq(NAME_mttr)), not_(eq(NAME_mtbf))), not_(eq(UNIT_mtbf)), not_(eq(DOT)), not_(eq(INT)), not_(eq(X_mttr)), not_(eq(X_mtbf))) ).interpretation( RULE.tresh ) rule_1 = (rule(NAME_mtbf, (TRESH.optional()).repeatable(), X_mtbf).repeatable() ).interpretation( RULE ) rule_2 = (rule(NAME_mttr, (TRESH.optional()).repeatable(), X_mttr).repeatable() ).interpretation( RULE ) f = open(path, 'r') text = f.read() #Remove line separators text = re.sub("^\s+|\n|\r|\s+$", '', text) line = text #Temporary workaround. Remove it as the performance grows n = 10000 text = [line[i-5 if i-5 > 0 else 0:i+n+5 if i+n+5 < len(line) else len(line) -1] for i in range(0, len(line), n)] MEASURE = rule(or_(X_mttr, X_mtbf, NAME_mttr, NAME_mtbf)) new_line = [] #Parser #1 text preprocessing parser = Parser(MEASURE) for line in text: matches = list(parser.findall(line)) spans = [_.span for _ in matches] new_span = [0, 0] if spans != [] and len(spans) >= 2: for i in range(0, len(spans)-1, 1): mini = 1000000 maxi = 0 if spans[i][0] < mini: new_span[0] = spans[i][0] mini = spans[i][0] if spans[i+1][1] > maxi: new_span[1] = spans[i+1][1] maxi = spans[i+1][1] for i in range(new_span[0], new_span[1]): new_line.append(line[i]) new_line.append(' \n ') new_line = ''.join(new_line) new_line = new_line.split('\n') LIST = [] MEASURE = or_(rule_1, rule_2).interpretation( RULE ) #Parser #2 Parsing reliability metrics. parser = Parser(MEASURE) for line in new_line: try: matches = list(parser.findall(line)) spans = [_.span for _ in matches] if spans != []: if matches: for match in matches: LIST.append(match.fact) except: print('Yargy failure: you normally don`t need to report that to us.') print(LIST) return LIST
VENDORS_NAME, VENDORS_ID = get_vendor_dict(tires_vendors_path) VENDOR = rule( caseless_pipeline(VENDORS_NAME).interpretation( Vendor.name.normalized().custom( VENDORS_NAME.get))).interpretation(Vendor) # TIRE_HELPERS DIAMETER_WITH_LETTER = rule(NUM, or_(eq('С'), eq('C')).optional()) STRUCTURE = or_( rule(or_(INT, FLOAT), SEP, or_(INT, FLOAT), SEP, or_(INT, DIAMETER_WITH_LETTER)), rule(or_(INT, FLOAT), SEP, or_(INT, FLOAT), eq('R'), or_(INT, DIAMETER_WITH_LETTER))) # TIRE_WIDTH WIDTH_PIPELINE = morph_pipeline(['шир', 'ширина', 'width', 'wid']) WIDTH = or_( rule(WIDTH_PIPELINE, SEP, or_(INT, FLOAT).interpretation(Tire.width), SEP), or_( rule( or_(INT, FLOAT).interpretation(Tire.width), SEP, or_(INT, FLOAT), SEP, or_(INT, DIAMETER_WITH_LETTER)), rule( or_(INT, FLOAT).interpretation(Tire.width), SEP, or_(INT, FLOAT), eq('R'), or_(INT, DIAMETER_WITH_LETTER)))).interpretation(Tire) # TIRE_PROFILE PROFILE_PIPELINE = morph_pipeline(['проф', 'профиль', 'prof', 'profile']) PROFILE = or_( rule(PROFILE_PIPELINE, SEP,
# BC # ########## SIMPLE_BC = or_( NOUN, ADJF ) COMPLEX_BC = morph_pipeline([ 'poklonka place', 'президент плаза', 'поклонка плейс', 'северное сияние', 'даниловская мануфактура', 'даниловский форт', 'корпус кнопа', 'чайка плаза', 'романов двор-2', 'золотая долина', 'Фаберже 8' ]) COMPLEX_BC_WORDS = morph_pipeline([ 'бизнес-центр', 'бизнес центр', 'бизнес-парк' ]) COMPLEX_ALC_WORDS = morph_pipeline([ 'архивно-логистический центр'
BuildingFact = fact('building', ['house', 'corpus', 'structure']) HouseNumber = rule( _type('INT'), rule( or_(rule(eq('/'), _type('INT')), rule(custom( lambda token: len(token) == 1)))).optional()).interpretation( BuildingFact.house) House = rule( rule( or_( StreetRule, rule( normalized('дом').repeatable(), normalized('номер').optional(), ))), HouseNumber) CorpusPrefix = morph_pipeline(['корпус', 'к']) Corpus = rule(CorpusPrefix, _type('INT').interpretation(BuildingFact.corpus)) StructurePrefix = morph_pipeline(['строение', 'ст']) Structure = rule(StructurePrefix, _type('INT').interpretation(BuildingFact.structure)) BuildingRule = rule(House, Corpus.optional(), Structure.optional()).interpretation(BuildingFact)
NUMINT ) NUM = or_( rule(NUMINT), FLOAT ) # Temperature Temperature = fact( 'Temperature', ['min', 'max', 'singular'] ) TEMPSIGN = morph_pipeline([ '°C', '°С' ]) SIGN = or_( rule('+'), rule('-') ) Num = fact( 'Num', ['n'] ) SIGNEDINT = rule( SIGN, NUMINT )
def __init__(self, logger=None, env='local'): self.env = env if logger is None: self.logger = logging.getLogger("LegalEntitiesExtractor") self.logger.setLevel(logging.DEBUG) handler = RotatingFileHandler("legal_entities_extractor.log", mode='a', encoding='utf-8', backupCount=5, maxBytes=1 * 1024 * 1024) formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) self.logger.addHandler(handler) else: self.logger = logger self.tokenizer = MorphTokenizer() self.morph = pymorphy2.MorphAnalyzer() self.NOUNS_TO_NORMALIZE = [ 'общество', 'объединение', 'учреждение', 'предприятие', 'департамент', 'организация', 'союз', 'центр' ] self.ADJ_TO_NORMALIZE_TO_NEUT = [ 'акционерный', 'публичный', 'музейный', 'государственный', 'казенный', 'казённый', 'унитарный' ] # LegalName = fact('LegalName', ['shortname', 'fullname']) # LegalForm = fact('LegalForm', ['shortform', 'fullform']) # LegalEnity = fact('LegalEnity', ['LegalForm','LegalName']) LEGAL_FORM_FULL = morph_pipeline([ 'общество с ограниченной ответственностью', 'акционерное общество', 'закрытое акционерное общество', 'открытое акционерное общество', 'акционерное общество управляющая компания', 'управляющая компания', 'публичное акционерное общество', 'музейное объединение', 'государственное казенное учреждение', 'государственное унитарное предприятие', 'департамент' ]) LEGAL_FORM_SHORT = morph_pipeline(['ПАО', 'ЗАО', 'ОАО', 'АО', 'ООО']) LEGAL_FORM = or_(LEGAL_FORM_SHORT, LEGAL_FORM_FULL) OPEN_QUOTE = or_(eq('\"'), eq('«'), eq('\'')) CLOSE_QUOTE = or_(eq('\"'), eq('»'), eq('\'')) INT = type('INT') LATIN = type('LATIN') FULL_NAME_SIMBOLS = or_(eq('&'), OPEN_QUOTE) SHORT_NAME_SIMBOLS = or_(eq('+'), eq('!'), eq('№')) LATIN_NAME_SIMBOLS = or_(eq('.'), eq('&')) GEO_TAG = rule(gram('NOUN'), gram('Geox')) WORD_IN_NAME = or_(gram('NOUN'), gram('ADJF'), gram('ADJS')) WORD_NOT_IN_SHORT_NAME = or_(eq('ИНН'), eq('ОГРН')) WORD_IN_SHORT_NAME = or_(gram('NOUN'), gram('ADJF')) WORD_IN_SHORT_NAME_FINAL = and_(WORD_IN_SHORT_NAME, not_(WORD_NOT_IN_SHORT_NAME)) WORD_IN_LATIN_NAME = or_(LATIN, LATIN_NAME_SIMBOLS) LATIN_NAME = rule(WORD_IN_LATIN_NAME.repeatable(min=2)) FULL_LEGAL_ENTITY = rule(LEGAL_FORM, GEO_TAG.optional(), OPEN_QUOTE, WORD_IN_NAME.repeatable(), CLOSE_QUOTE) SIMPLE_LEGAL_ENTITY = rule(LEGAL_FORM_SHORT, WORD_IN_SHORT_NAME_FINAL) GOV_ENTITY = rule(LEGAL_FORM_FULL, WORD_IN_SHORT_NAME.repeatable(min=1)) LEGAL_ENTITY = or_(FULL_LEGAL_ENTITY, SIMPLE_LEGAL_ENTITY, GOV_ENTITY) self.full_legal_parser = Parser(LEGAL_ENTITY) self.legal_form_parser = Parser(LEGAL_FORM) self.legal_latin_parser = Parser(LATIN_NAME)
from yargy.interpretation import fact from yargy.predicates import gram, eq, type, in_ from yargy.relations import gnc_relation from yargy.pipelines import morph_pipeline from .data import NCONTRACT INT = type('INT') DOT = eq('.') LEFT = eq('<') RIGHT = rule(in_('>.')) Datecont = fact('Datecont', ['day', 'month', 'year']) OT = rule(eq('от')) BEFOREDATE = or_(NCONTRACT, OT) DAY = rule(INT).interpretation(Datecont.day.custom(int)) MONTH = or_( morph_pipeline([ 'январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь' ]), rule(INT)).interpretation(Datecont.month) YEAR = rule(INT).interpretation(Datecont.year.custom(int)) #Правило для даты документа DATECONT = rule(BEFOREDATE, LEFT.optional(), DAY, RIGHT.optional(), MONTH, DOT.optional(), YEAR).interpretation(Datecont)
from yargy import or_, rule from yargy.predicates import normalized RULE = or_( rule(normalized('dvd'), '-', normalized('диск')), rule(normalized('видео'), normalized('файл')) ) from yargy import Parser from yargy.pipelines import morph_pipeline RULE = morph_pipeline([ 'dvd-диск', 'видео файл', 'видеофильм', 'газета', 'электронный дневник', 'эссе', ]) parser = Parser(RULE) text = 'Видео файл на dvd-диске' for match in parser.findall(text): print([_.value for _ in match.tokens]) from yargy import Parser, rule, and_ from yargy.predicates import gram, is_capitalized, dictionary GEO = rule( and_(
).interpretation(const(10**3)) MILLION = or_( rule(caseless('млн'), DOT.optional()), rule(normalized('миллион')) ).interpretation(const(10**6)) MILLIARD = or_( rule(caseless('млрд'), DOT.optional()), rule(normalized('миллиард')) ).interpretation(const(10**9)) TRILLION = or_( rule(caseless('трлн'), DOT.optional()), rule(normalized('триллион')) ).interpretation(const(10**12)) MULTIPLIER = or_( THOUSANDTH, HUNDREDTH, TENTH, THOUSAND, MILLION, MILLIARD, TRILLION ).interpretation(Number.multiplier) NUM_RAW = rule(morph_pipeline(NUMS_RAW).interpretation(Number.int.normalized().custom(NUMS_RAW.get))) NUM_INT = rule(INT).interpretation(Number.int.custom(int)) NUM = or_( NUM_RAW, NUM_INT ).interpretation(Number.int) NUMBER = or_( rule(NUM, MULTIPLIER.optional()) ).interpretation(Number)
from yargy.pipelines import morph_pipeline #проверка на то, число ли это def is_number(string): for c in string: if ((ord(c) < 48 or ord(c) > 57)): return False return True is_number_ = custom(is_number) #правило понимает дроби NUMBER_RULE = rule(or_(gram("NUMR"), is_number_)) #все приставки, означающие денки: MONEY_PIPE = morph_pipeline(["тыс", "к", "k", "м", "руб", "рублей", "тысяч"]) #поиск токенов, означающих цену #нижнюю границу PRICE_FROM = rule(morph_pipeline(["от", "дороже"]), NUMBER_RULE.repeatable(), MONEY_PIPE.optional().repeatable()) #верхнюю границу PRICE_TO = rule( morph_pipeline(["до", "дешевле", "дешевле чем", "дешевле, чем"]), NUMBER_RULE.repeatable(), MONEY_PIPE.optional().repeatable()) #точное значение PRICE_VALUE = rule(NUMBER_RULE.repeatable(), not_(dictionary({"%", "процент", "процентов"})), MONEY_PIPE.optional().repeatable()) #поиск атрибутов. #Note: в строку атрибутов входит название самого товара
POSITION = morph_pipeline([ 'святой', 'патриарх', 'митрополит', 'царь', 'король', 'царица', 'император', 'императрица', 'принц', 'принцесса', 'князь', 'граф', 'графиня', 'барон', 'баронесса', 'княгиня', 'президент', 'премьер-министр', 'экс-премьер', 'пресс-секретарь', 'министр', 'замминистр', 'заместитель', 'глава', 'канцлер', 'помощник', 'посол', 'губернатор', 'председатель', 'спикер', 'диктатор', 'лидер', 'генсек', 'премьер', 'депутат', 'вице-премьер', 'сенатор', 'полпред', 'госсекретарь', 'вице-президент', 'сопредседатель', 'зам', 'мэр', 'вице-спикер', 'замруководителя', 'зампред', 'муфтий', 'спецпредставитель', 'руководитель', 'статс-секретарь', 'зампредседатель', 'представитель', 'ставленник', 'мадеро', 'вице-губернатор', 'зампредсовмин', 'наркоминдела', 'генпрокурор', 'комиссар', 'рейхсканцлер', 'советник', 'замглавы', 'секретарь', 'парламентарий', 'замгендиректор', 'вице-председатель', 'постпред', 'госкомтруд', 'предсовмин', 'преемник', 'делегат', 'шеф', 'консул', 'замминистра', 'главкомпис', 'чиновник', 'врио', 'управделами', 'нарком', 'донпродкомиссар', 'председ', 'гендиректор', 'генерал-губернатор', 'обревком', 'правитель', 'замсекретарь', 'главнокомандующий', 'вице-мэр', 'наместник', 'спичрайтер', 'вице-консул', 'мвэс', 'облревком', 'главковерх', 'пресс-атташе', 'торгпред', 'член', 'назначенец', 'эмиссар', 'обрядоначальник', 'главком', 'единоросс', 'политик', 'генерал', 'замгенпрокурор', 'дипломат', 'главноуполномоченный', 'генерал-фельдцейхмейстер', 'комендант', 'казначей', 'уполномоченный', 'обер-прокурор', 'наркомзем', 'соправитель', 'основатель', 'сооснователь', 'управляющий директор', 'управляющий партнер', 'партнер', 'руководитель', 'аналитик', 'зампред', 'миллиардер', 'миллионер', 'автор', 'актер', 'актриса', 'певец', 'певица', 'исполнитель', 'солист', 'режиссер', 'сценарист', 'писатель', 'музыкант', 'композитор', 'корреспондент', 'журналист', 'редактор', 'дирижер', 'кинорежиссер', 'звукорежиссер', 'детектив', 'пианист', 'драматург', 'артист', 'балетмейстер', 'скрипач', 'хореограф', 'танцовщик', 'документалист', 'поэт', 'литератор', 'киноактер', 'вокалист', 'бард', 'комик', 'продюсер', 'кинодраматург', 'киноактриса', 'балерина', 'пианистка', 'критик', 'танцор', 'концертмейстер', 'симфонист', 'сатирик', 'аранжировщик', 'саксофонист', 'юморист', 'шансонье', 'гастролер', 'виолончелист', 'постановщик', 'кинематографист', 'сценограф', 'джазмен', 'музыковед', 'киноартист', 'педагог', 'хормейстер', 'беллетрист', 'примадонна', 'инструменталист', 'альтист', 'шоумен', 'виртуоз', 'пародист', 'декоратор', 'модельер', 'очеркист', 'оперетта', 'контрабасист', 'карикатурист', 'дуэт', 'монтажер', 'живописец', 'скульптор', 'режиссура', 'архитектор', 'антрепренер', 'импрессарио', 'прозаик', 'труппа', 'трагик', 'клоун', 'солистка', 'либреттист', 'литературовед', 'портретист', 'гример', 'художник', 'импровизатор', 'декламаторша', 'телеведущий', 'импресарио', 'мастер', 'аккомпаниатор', 'шахматист', 'иллюзионист', 'эстрадник', 'эстрада', 'спортсмен', 'дизайнер', 'кинокритик', 'публицист', 'чтец', 'конферансье', 'студиец', 'коверный', 'куплетист', 'знаменитость', 'ученый', 'балет', 'искусствовед', 'гитарист', 'доктор', 'академик', 'судья', 'юрист', 'представитель', 'директор', 'прокурор', 'отец', 'мать', 'мама', 'папа', 'брат', 'сестра', 'тёща', 'тесть', 'дедушка', 'бабушка', 'жена', 'муж', 'дочь', 'сын', 'мистер', 'миссис', 'господин', 'госпожа', 'пан', 'пани', 'сэр', 'мисс', 'боксер', 'боец', 'атлет', 'футболист', 'баскетболист', 'агроном', 'президент', 'сопрезидент', 'вице-президент', 'экс-президент', 'председатель', 'руководитель', 'директор', 'глава', ])
def extract(text): with open(os.path.join(os.getcwd(), 'list_diseases/diseases'), encoding='utf-8') as f: diseases = f.read().split('\n') text = text.replace('\ufeff', '') text = text.replace('\n', ' \n ') text = text.replace('\\', ' ') symptoms = ['Дата рождения', 'Дата осмотра','Дата заболевания', 'Возраст', 'Болен дней','Болен часов','Возраст в днях','Время поступления', 'Время заболевания', 'рост','вес', 'IMT', 'давление диаст', 'давление сист', 'температура поступления','мах температура', 'пол', 'др заболевания в анамнезе', 'побочное действие лекартсв','аллергическая реакция', 'озноб', 'слабость', 'вялость','головная боль', 'нарушение сна', 'нарушение аппетита', 'ломота','тошнота', 'нарушение сознания', 'Судороги', 'Парестезии', 'эритема', 'с четкими границами', 'валик', 'боль','Гиперемия', 'Отек', 'Лимфаденит', 'Лимфангит', 'квартира, дом','контакт с зараженными','речная рыба','провоцирущие факторы', 'предрасполагающие факторы','кол-во сопут заболеваний','соц категория','сопутствующий диагноз','основной диагноз', 'контакт с зараженными', 'пищевой анамнез', 'раневые ворота', 'аллергия на лекарства', 'клещ', 'географический анамнез', 'вредные привычки', 'домашние животные', 'условия труда','избыточное питание', 'бытовые условия', 'питание', 'интоксикация', 'ЧСС', 'болезненность лимфоузлов', 'увеличенность лимфоузлов','размер лимфоузлов', 'острое начало'] dict_symp = dict.fromkeys(symptoms) dates_lst = [] # Rule for dates detecting DAY = and_(gte(1),lte(31)) MONTH = and_(gte(1),lte(12)) YEAR = and_(gte(1),lte(19)) YEARFULL = and_(gte(1900),lte(2020)) DATE = or_( rule(YEAR,'.',MONTH,'.',DAY), rule(DAY,'.',MONTH,'.',YEAR), rule(DAY,'.',MONTH,'.',YEARFULL), rule(DAY,'.',MONTH), rule(DAY,'.',MONTH,YEARFULL), rule(DAY,'.',MONTH,YEAR)) parser = Parser(DATE) for match in parser.findall(text): dates_lst.append(''.join([_.value for _ in match.tokens])) # Sometimes we dont have information about birthday and we should check difference between years # in first two dates to determine there is information about birthday or not try: if int(dates_lst[1][-2:])-int(dates_lst[0][-2:])<0: # According medical cards dates have this order dict_symp['Дата рождения'] = dates_lst[0] dict_symp['Дата осмотра'] = dates_lst[1] dict_symp['Дата заболевания'] = dates_lst[2] else: birth = None dict_symp['Дата осмотра'] = dates_lst[0] dict_symp['Дата заболевания'] = dates_lst[1] except: pass # If date was written without year, we take year from previous date try: if len(dict_symp['Дата заболевания'])==5: dict_symp['Дата заболевания'] += dict_symp['Дата осмотра'][dict_symp['Дата осмотра'].rfind('.'):] except: pass # Rule for detecring dates with such situation "болен 5 дней" DAY_RULE = morph_pipeline(['дней']) parser = Parser(DAY_RULE) day_lst = [] for match in parser.findall(text): day_lst.append((match.span, [_.value for _ in match.tokens])) try: if day_lst and dict_symp['Дата заболевания'] is None: dict_symp['Дата заболевания'] = text[day_lst[0][0][0]-20:day_lst[0][0][0]+20] dict_symp['Дата заболевания'] = re.findall(r'\d+', dict_symp['Дата заболевания'])[0] dict_symp['Дата заболевания'] = str(int(dict_symp['Дата осмотра'][:2])-int(dict_symp['Дата заболевания'])) dict_symp['Дата заболевания'] = dict_symp['Дата заболевания']+dict_symp['Дата осмотра'][2:] except: pass # Rule for detecting Age age_lst = [] AGE = and_(gte(0),lte(100)) AGE_RULE = or_(rule("(",AGE,")"), rule(gram('ADJF'),",",AGE)) parser = Parser(AGE_RULE) for match in parser.findall(text): s = ''.join([_.value for _ in match.tokens]) age_lst.append((re.findall(r'\d+', s)[0])) try: if age_lst: dict_symp['Возраст'] = int(age_lst[-1]) except: pass # Transform dates to datetime format to make calculations if dict_symp['Дата осмотра'] and (dict_symp['Дата заболевания']): try: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%Y') except: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%y') d1 = d1.strftime('%d.%m.%Y') d1 = datetime.strptime(d1, '%d.%m.%Y') try: d2 = datetime.strptime(dict_symp['Дата заболевания'], '%d.%m.%Y') except: d2 = datetime.strptime(dict_symp['Дата заболевания'], '%d.%m.%y') d2 = d2.strftime('%d.%m.%Y') d2 = datetime.strptime(d2, '%d.%m.%Y') try: dict_symp['Болен дней'] = (d1 - d2).days dict_symp['Болен часов'] = (int(dict_symp['Болен дней'])-1)*24 except: pass try: if dict_symp['Дата рождения'] is None: dict_symp['Возраст в днях'] = int(dict_symp['Возраст'])*365 else: d1 = datetime.strptime(dict_symp['Дата осмотра'], '%d.%m.%Y') d2 = datetime.strptime(dict_symp['Дата рождения'], '%d.%m.%Y') dict_symp['Возраст в днях'] = (d1 - d2).days except: pass # Rule for time detecting time_lst = [] time_spans = [] HOURS = and_(gte(0),lte(24)) MINUTES = and_(gte(0),lte(59)) TIME = or_(rule(HOURS,':',MINUTES), rule(HOURS, normalized('час')),) parser = Parser(TIME) for match in parser.findall(text): s = (''.join([_.value for _ in match.tokens])) time_spans.append(match.span) s = s.replace('часов', ':00') s = s.replace('час', ':00') time_lst.append(s) # if we have only 1 date 'Время поступления' = 'Время заболевания' if time_lst: dict_symp['Время поступления'] = time_lst[0] dict_symp['Время заболевания'] = time_lst[0] dict_index['Время поступления'] = time_spans[0] dict_index['Время заболевания'] = time_spans[0] try: if len(time_lst)>1: dict_symp['Время заболевания'] = time_lst[1] dict_index['Время заболевания'] = time_spans[1] except: pass t1 = dict_symp['Время поступления'] t2 = dict_symp['Время заболевания'] try: delta = int(t1[:t1.find(':')])+24-int(t2[:t2.find(':')]) dict_symp['Болен часов'] = dict_symp['Болен часов'] + delta except: pass # Rules for detecting Weight, Height and IMT HEIGHT = and_(gte(50),lte(250)) WEIGHT = and_(gte(10),lte(150)) HEIGHT_RULE = or_(rule(normalized('рост'),'-',HEIGHT), rule(normalized('рост'),'–',HEIGHT), rule(normalized('рост'),':',HEIGHT), rule(normalized('рост'),HEIGHT)) WEIGHT_RULE = or_(rule(normalized('вес'),'-',WEIGHT), rule(normalized('вес'),'–',WEIGHT), rule(normalized('вес'),':',WEIGHT), rule(normalized('вес'),WEIGHT)) height = None parser = Parser(HEIGHT_RULE) for match in parser.findall(text): height = (''.join([_.value for _ in match.tokens])) height = re.findall(r'\d+', height)[0] try: if height: dict_symp['рост'] = int(height) except: pass weight = None parser = Parser(WEIGHT_RULE) for match in parser.findall(text): weight = (''.join([_.value for _ in match.tokens])) weight = re.findall(r'\d+', weight)[0] try: if weight: dict_symp['вес'] = int(weight) if (dict_symp['рост'] is not None) and (dict_symp['вес'] is not None): dict_symp['IMT'] = round(dict_symp['вес']/(dict_symp['рост']/100*dict_symp['рост']/100),2) except: pass # Rules for detecting pressure ADSIST = and_(gte(50),lte(250)) ADDIAST = and_(gte(20),lte(200)) PRES_RULE = or_(rule('АД', ADSIST,'/',ADDIAST), rule('АД', ADSIST,ADDIAST), rule('АД', ADSIST, ':',ADDIAST), rule('АД','-', ADSIST, '/',ADDIAST), rule('А/Д', ADSIST, '/',ADDIAST), rule('А/Д', ADSIST, ADDIAST), rule('А/Д',' ', ADSIST, '/',ADDIAST), rule(ADSIST, '/',ADDIAST)) pres = None parser = Parser(PRES_RULE) for match in parser.findall(text): pres = (''.join([_.value for _ in match.tokens])) pres = re.findall(r'\d+', pres) try: if pres: dict_symp['давление сист'] = int(pres[0]) dict_symp['давление диаст'] = int(pres[1]) except: pass # Rule for detecting Pulse PULSE = and_(gte(40),lte(150)) PULSE_RULE = or_(rule('ЧСС','-',PULSE), rule('ЧСС',PULSE), rule('ЧСС','-',PULSE), rule('ЧСС','/',PULSE), rule('пульс',PULSE),) pulse = None parser = Parser(PULSE_RULE) for match in parser.findall(text): pulse = (''.join([_.value for _ in match.tokens])) pulse = re.findall(r'\d+', pulse) try: if pulse: dict_symp['ЧСС'] = int(pulse[0]) except: pass #Rules for detecting temperatures DEGREES = and_(gte(34),lte(42)) SUBDEGREES = and_(gte(0),lte(9)) TEMP_RULE = or_(rule(DEGREES,',',SUBDEGREES), rule(DEGREES,'.',SUBDEGREES), rule(DEGREES)) # Find 'Объективный статус', because this pert contains information about 'температура поступления' status = text[text.find('Объективный статус'): text.find('Объективный статус')+text[text.find('Объективный статус')+1:].find(' \n \n')] temp_lst = [] parser = Parser(TEMP_RULE) for match in parser.findall(status): temp_lst.append(''.join([_.value for _ in match.tokens])) if temp_lst: dict_symp['температура поступления'] = temp_lst[0] # Find temperatures in whole text temp_text = text[text.find('Жалобы'):] temp_lst = [] parser = Parser(TEMP_RULE) for match in parser.findall(temp_text): temp_lst.append(''.join([_.value for _ in match.tokens])) if temp_lst: if dict_symp['температура поступления'] is None: dict_symp['температура поступления'] = temp_lst[0] dict_symp['мах температура'] = max([float(i.replace(',','.')) for i in temp_lst]) # Rule for detecting Sex sex_lst = [] SEX_RULE = or_(rule(normalized('женский')), rule(normalized('мужской'))) parser = Parser(SEX_RULE) for match in parser.findall(text): sex_lst.append(''.join([_.value for _ in match.tokens])) try: if sex_lst: dict_symp['пол'] = sex_lst[0] dict_symp['пол'] = dict_symp['пол'].lower().replace('женский', '2') dict_symp['пол'] = dict_symp['пол'].lower().replace('мужской', '1') dict_symp['пол'] = int(dict_symp['пол']) except: pass # Rule for detecting DISEASES DISEASES_RULE = morph_pipeline(diseases[:-1]) # anamnez contains information about diseases of patient, but family anamnez contains # information about diseases of patient, and we should remove this part anamnez = text[text.find('Анамнез'): text.find('Анамнез')+text[text.find('Анамнез')+1:].rfind('Анамнез')] family = anamnez[anamnez.find('Семейный'):anamnez.find('Семейный')+60] if family: anamnez = anamnez.replace(family,' ') anamnez = anamnez[:anamnez.rfind('Диагноз')] dis_lst = [] parser = Parser(DISEASES_RULE) for match in parser.findall(anamnez): dis_lst.append(' '.join([_.value for _ in match.tokens])) # Special rule for описторхоз OP_RULE = or_(rule(normalized('описторхоз'), not_(normalized('не')))) parser = Parser(OP_RULE) op_lst = [] for match in parser.findall(anamnez):#text op_lst.append((match.span, [_.value for _ in match.tokens])) if op_lst: dis_lst.append(' описторхоз') # Special rule for туберкулез TUB_RULE = rule(normalized('туберкулез'), not_(normalized('отрицает'))) parser = Parser(TUB_RULE) tub_lst = [] for match in parser.findall(anamnez):#text tub_lst.append((match.span, [_.value for _ in match.tokens])) if tub_lst: dis_lst.append(' туберкулез') if dis_lst: dis_lst = list(set(dis_lst)) dict_symp['др заболевания в анамнезе'] = ', '.join(dis_lst) dict_symp['др заболевания в анамнезе'] = morph.parse(dict_symp['др заболевания в анамнезе'])[0].normal_form # Rule for allergy ALLERG_RULE = or_(rule(normalized('Аллергическая'),normalized('реакция'), normalized('на')), rule(normalized('не'),normalized('переносит'))) all_lst = [] parser = Parser(ALLERG_RULE) for match in parser.findall(text): all_lst.append((list(match.span), [_.value for _ in match.tokens])) if all_lst: index = all_lst[0][0][1] dict_symp['аллергическая реакция'] = text[index:text[index:].find('.')+index] # Rules for different symptoms symptoms = [['озноб', 'познабливание'], 'слабость', ['вялость', 'разбитость'],'головная боль', 'нарушение сна', 'нарушение аппетита', 'ломота','тошнота', 'нарушение сознания','Судороги', 'Парестезии', ['эритема', 'эритематозная', 'эритематозно'], ['с четкими границами', 'границами четкими', 'четкими неровными краями', 'с четкими краями', 'краями четкими' , 'четкими неровными краями', 'четкими контурами', 'языков пламени'], ['валик', 'вал'], 'боль',['Гиперемия', 'гиперемирована'], 'Отек', 'Лимфангит', ['рана', "раневые ворота", "входные ворота"],['клещ', "присасывание"], 'интоксикация', 'острое начало'] for i in symptoms: sym_lst = [] if isinstance(i, str): SYM_RULE = morph_pipeline([i]) parser = Parser(SYM_RULE) for match in parser.findall(text): sym_lst.append(' '.join([_.value for _ in match.tokens])) if sym_lst: dict_symp[i] = 1 else: dict_symp[i] = 0 else: SYM_RULE = morph_pipeline(i) parser = Parser(SYM_RULE) for match in parser.findall(text): sym_lst.append(' '.join([_.value for _ in match.tokens])) if sym_lst: dict_symp[i[0]] = 1 else: dict_symp[i[0]] = 0 #This fuction used for features which have the same rule def find_feature(feature, RULE, RULE2, space=[40,40]): parser = Parser(RULE) lst = [] for match in parser.findall(text): lst.append((match.span, [_.value for _ in match.tokens])) if lst: add_text = text[list(match.span)[1]-space[0]:list(match.span)[1]+space[1]] parser = Parser(RULE2) lst = [] for match in parser.findall(add_text): lst.append((match.span, [_.value for _ in match.tokens])) if lst: dict_symp[feature] = 1 else: dict_symp[feature] = 0 GEO_RULE = morph_pipeline(['географический', 'выезжал']) GEO_RULE2 = rule(not_(normalized('не')),normalized('выезжал')) geo_space = [40,40] COND_RULE = morph_pipeline(['бытовые']) COND_RULE2 = rule(not_(normalized('не')),normalized('удовлетворительные')) cond_space = [0,60] SEC_COND_RULE = morph_pipeline(['Социально-бытовые']) sec_cond_space = [0,60] WORK_COND_RULE = morph_pipeline(['условия труда']) work_cond_space = [20,20] CONTACT_RULE = morph_pipeline(['контакт']) CONTACT_RULE2 = morph_pipeline(['да']) contact_space = [0,40] WATER_RULE = morph_pipeline(['сырой воды']) WATER_RULE2 = morph_pipeline(['не было', 'отрицает', 'нет']) water_space = [80,80] features = ['географический анамнез', 'бытовые условия', 'бытовые условия', 'условия труда','контакт с зараженными','пищевой анамнез'] rules = [GEO_RULE, COND_RULE, SEC_COND_RULE, WORK_COND_RULE, CONTACT_RULE, WATER_RULE] sec_rules = [GEO_RULE2, COND_RULE2, COND_RULE2, COND_RULE2, CONTACT_RULE2, WATER_RULE2] spaces = [geo_space, cond_space, sec_cond_space, work_cond_space, contact_space, water_space] for i in range(len(features)): find_feature(features[i],rules[i],sec_rules[i],spaces[i]) # Rules for bad habbits HAB_RULE = morph_pipeline(['вредные привычки', 'алкоголь']) parser = Parser(HAB_RULE) hab_lst = [] for match in parser.findall(text): hab_lst.append((match.span, [_.value for _ in match.tokens])) if hab_lst: text_hab = text[list(match.span)[1]-80:list(match.span)[1]+80] HAB_RULE = morph_pipeline(['не было', 'отрицает', 'нет', 'не употребляет']) parser = Parser(HAB_RULE) hab_lst = [] for match in parser.findall(text_hab): hab_lst.append((match.span, [_.value for _ in match.tokens])) if hab_lst: dict_symp['вредные привычки'] = 0 else: dict_symp['вредные привычки'] = 1 SMOKE_RULE = or_(rule(not_(normalized('не')),normalized('курит')), rule(not_(normalized('не')),normalized('употребляет'))) parser = Parser(SMOKE_RULE) hab_lst = [] for match in parser.findall(text): hab_lst.append((match.span, [_.value for _ in match.tokens])) if hab_lst: dict_symp['вредные привычки'] = 1 # Rules for work work_lst = [] WORK_RULE = morph_pipeline(['работает']) parser = Parser(WORK_RULE) for match in parser.findall(text): work_lst.append((match.span, [_.value for _ in match.tokens])) if work_lst: dict_symp['соц категория'] = 0 WORK_RULE = rule(not_(normalized('не')),normalized('работает')) parser = Parser(WORK_RULE) work_lst = [] for match in parser.findall(text): work_lst.append((match.span, [_.value for _ in match.tokens])) if work_lst: dict_symp['соц категория'] = 1 # If patient has условия труда probably he has a job if dict_symp['условия труда'] is not None: dict_symp['соц категория'] = 1 # Rule for fish FISH_RULE = morph_pipeline(['рыба']) parser = Parser(FISH_RULE) fish_lst = [] for match in parser.findall(text): fish_lst.append((match.span, [_.value for _ in match.tokens])) if fish_lst: dict_symp['речная рыба'] = 0 text_fish = text[list(match.span)[1]-40:list(match.span)[1]+40] FISH_RULE = morph_pipeline(['да', 'постоянно']) parser = Parser(FISH_RULE) fish_lst = [] for match in parser.findall(text_fish): fish_lst.append((match.span, [_.value for _ in match.tokens])) if fish_lst: dict_symp['речная рыба'] = 1 FISH_RULE = rule(not_(normalized('не')),normalized('употребляет')) parser = Parser(FISH_RULE) fish_lst = [] for match in parser.findall(text_fish): fish_lst.append((match.span, [_.value for _ in match.tokens])) if fish_lst: dict_symp['речная рыба'] = 1 # Rule for home home = None home_span = None home_types = [['бездомный'], ['дом благоустроенный', 'частный дом'], ['дом не благоустроенный','дом неблагоустроенный'], ['квартира не благоустроенная', 'квартира неблагоустроенная'], ['квартира благоустроенная', 'благоустроенная квартира'],] for i in range(len(home_types)): home_lst = [] HOME_RULE = morph_pipeline(home_types[i]) parser = Parser(HOME_RULE) for match in parser.findall(text): home_lst.append((match.span, [_.value for _ in match.tokens])) if home_lst: home = i home_span = match.span dict_symp['квартира, дом'] = home pets = [] pets_span = [] pet_types = [['кошка'], ['собака'], ['корова','коза']] # Rules for different factors factors = [] factors_span = [] factor_types = [['ссадины',"царапины", "раны", "расчесы", "уколы", "потертости", "трещины", 'вскрытие', 'поцарапал', "рассечен"], ['ушибы'], ['переохлаждение','перегревание','смена температуры',"охлаждение"], ['инсоляция'], ['лучевая терапия'], ['стресс', "стрессовая ситуация"], ['переутомление', 'тяжело работал']] def find_factors(factor_types, text=text, left=0, right=len(factor_types)): for i in range(len(factor_types[left:right])): factor_lst = [] FACT_RULE = morph_pipeline(factor_types[i+left]) parser = Parser(FACT_RULE) for match in parser.findall(text): factor_lst.append(' '.join([_.value for _ in match.tokens])) factors_span.append(match.span) if factor_lst: factors.append(i+1+left) find_factors(factor_types) detect_lst = [] parser = Parser(morph_pipeline(['трещин - не обнаружено'])) for match in parser.findall(text): detect_lst.append(' '.join([_.value for _ in match.tokens])) if detect_lst: factors.remove(1) if factors: dict_symp['провоцирущие факторы'] = factors factors = [] factor_types = [['микоз',"диабет", "ожирение", "варикоз", "недостаточность", "лимфостаз", "экзема", "варикозная болезнь"], ['тонзилит',"отит", "синусит", "кариес", "пародонтоз", "остеомиелит", "тромбофлебит", "трофические язвы"], ['резиновая обувь','загрязнения кожных'], ['соматические заболевания']] if dict_symp['др заболевания в анамнезе']: find_factors(factor_types, text=dict_symp['др заболевания в анамнезе'], right=2) find_factors(factor_types, left=2) if factors: dict_symp['предрасполагающие факторы'] = factors # Rule for detecting the second diagnosis DIAGNOZ_RULE = or_(rule(normalized('сопутствующий'), not_(or_(gram('NOUN')))), rule(normalized('сопутствующий'),normalized('диагноз')), rule(normalized('диагноз'),normalized('сопутствующий')),) parser = Parser(DIAGNOZ_RULE) diag_lst = [] for match in parser.findall(text): diag_lst.append((match.span, [_.value for _ in match.tokens])) if diag_lst: dict_symp['сопутствующий диагноз'] = text[list(match.span)[1]+2:list(match.span)[1]+text[list(match.span)[1]:].find(' \n \n')] dict_symp['кол-во сопут заболеваний'] = dict_symp['сопутствующий диагноз'].count('\n') if dict_symp['кол-во сопут заболеваний']==0: dict_symp['кол-во сопут заболеваний']=1 # Rule for detecting the first diagnosis DIAGNOZ_RULE = or_(rule(normalized('диагноз'),normalized('при'),normalized('поступлении')), rule(normalized('клинический'),normalized('диагноз')), rule(normalized('диагноз'),normalized('клинический')), rule(normalized('основной'),normalized('диагноз')), rule(normalized('диагноз'),normalized('основной')), rule(normalized('Ds')), rule(normalized('Ds:')), rule(not_(or_(gram('ADJF'),gram('NOUN'))),normalized('диагноз'),not_(or_(gram('ADJF'),gram('PREP'))))) diag_lst = [] parser = Parser(DIAGNOZ_RULE) for match in parser.findall(text): diag_lst.append((match.span, [_.value for _ in match.tokens])) last = list(match.span)[1]+text[list(match.span)[1]:].find(' \n \n') if last == list(match.span)[1]-1: last = len(text)-1 dict_symp['основной диагноз'] = text[list(match.span)[1]+1:last] return dict_symp
NUMBERS.repeatable().optional().interpretation(COD.n7), rule(normalized('глава')).repeatable().optional().interpretation(COD.chapter), NUMBERS.repeatable().optional().interpretation(COD.n8), gram('ADJF').repeatable().interpretation(COD.type), morph_pipeline({ 'гк', 'нк', 'тк', 'ук', 'гпк', 'упк', 'апк', 'жк', 'ск', 'уик', 'кодекс' }).interpretation(COD.codex.const('Кодекс')) ).interpretation(COD) COURT = rule( gram('NOUN').repeatable().optional().interpretation(COURT_.smth), gram('ADJF').repeatable().interpretation(COURT_.type), morph_pipeline({ 'кс', 'вс', 'вас',
from yargy import or_, rule from yargy.interpretation import fact from yargy.pipelines import morph_pipeline from yargy.predicates import caseless, custom, eq, in_ from .common import TOKENIZER Time = fact('Time', ['hours', 'minutes']) hour_re = re.compile(r'([01]\d|\d|2[0-3])') is_hour = custom(hour_re.fullmatch).activate(TOKENIZER) minute_re = re.compile(r'[0-5]\d') is_minute = custom(minute_re.fullmatch).activate(TOKENIZER) HOUR_UNIT = rule(morph_pipeline(['ч', 'час', 'часы']), eq('.').optional()) MINUTE_UNIT = rule(morph_pipeline(['м', 'мин', 'минуты']), eq('.').optional()) # 17:02 ч. TIME_DIGITAL = rule( is_hour.means(Time.hours), in_(':-.'), is_minute.means(Time.minutes), or_(HOUR_UNIT, MINUTE_UNIT).optional(), ).means(Time) # 17ч 02 TIME_HUMAN = rule( is_hour.means(Time.hours), HOUR_UNIT,
LEVEL = rule( caseless_pipeline([ 'junior', 'middle', 'senior', 'lead', 'chief', 'head', 'team lead', "старший", "младший", "руководитель направления" ]).interpretation(Position.level)) # TODO: нужно учесть жаргонные варианты (датасаентолог, датасатанист и т.д.) Скорее всего, придется парсить регулярками NAME = rule( or_( caseless_pipeline([ 'data scientist', 'data engineer', 'engineer', 'analyst', 'data analyst', 'data manager', 'scientist', 'researcher', "developer", "intern" ]), rule(dictionary(['DS', 'DE']), is_capitalized()), morph_pipeline(["аналитик", "разработчик", "стажер"])).interpretation(Position.name.inflected())) FIELD = rule( caseless_pipeline([ 'ML', 'DL', 'CV', 'computer vision', 'NLP', 'bi', 'machine learning', 'deep learning', 'software', 'research', 'big data', 'python', 'c++', "scala", "java", 'ios', "android", 'devops', "backend", 'frontend' ]).interpretation(Position.field)) HEAD = rule( caseless('head').interpretation(Position.level), eq('of'), caseless_pipeline(['analytics', 'predictive analytics', 'data science']).interpretation(Position.field)) POSITION = or_( rule(LEVEL.optional(), FIELD.optional(),
import os import en_core_web_sm def get_mosmetro_stations(): path = os.path.abspath(os.path.dirname(__file__)) df = pd.read_csv(path + '/mosmetro.csv', encoding='utf-8') return df[df.Status == 'действует'].Station.values stations = get_mosmetro_stations() Mosmetro = fact('mosmetro', ['name']) MOSMETRO = rule(or_(rule(eq('метро')), rule(eq('м'), eq('.'))), morph_pipeline(stations).interpretation( Mosmetro.name)).interpretation(Mosmetro) Location = fact( 'Location', [ 'name', 'region_or_island', 'ao_or_fo', 'federation', 'adjx_federation', 'state', 'locality', 'sea', 'island' ], ) gnc = gnc_relation() LOCALITY = rule( and_( dictionary({ 'город', # 'деревня',
def __init__(self): super(NerTimeCount, self).__init__() self.last_request = None self.last_result = [None, None, None] self.name = 'TimeCount' # переводим числа от 1 до 59 в текст n2t60 = [n2t(i) for i in range(1, 60)] # для поиска порядковых числительных def not_coll_numbers(x): return ('NUMR' in str(morph.parse(x)[0].tag) and ('Coll' not in str(morph.parse(x)[0].tag))) or x == 'один' # часы в словах hours_t = and_(dictionary(n2t60[:24] + ["полтора", "полдень"]), custom(not_coll_numbers)) # минуты в словах minutes_t = dictionary(n2t60) coll_numbers_dic = dictionary( ["двое", "трое", "четверо", "пятеро", "шестеро", "семеро"]) list_0n = {"00", "01", "02", "03", "04", "05", "06", "08", "09"} # часы в цифрах hours_n = or_(and_(gte(1), lte(23)), in_(list_0n)) # минуты в цифрах minutes_n = or_(and_(gte(1), lte(59)), in_(list_0n)) # разделитель в чч_мм two_points = dictionary([":"]) separator = dictionary([":", "."]) # определяем предлоги pr_v = rule("в") pr_ok = rule("около") pr_vrayone = morph_pipeline(["В районе"]) pr_k = rule("к") pr_na = rule("на") pr_c = rule("с") start_prepositions = or_(pr_ok, pr_v, pr_k, pr_na, pr_c, pr_vrayone) pr_vtech = morph_pipeline(["в течение"]) pr_do = rule("до") pr_po = rule("по") duration_prepositions = or_(pr_vtech, pr_do, pr_po) # отрезки времени суток day_periods = or_(rule(normalized("утро")), rule(normalized("день")), rule(normalized("вечер"))) # час - особый случай, т.к. сам обозначает определённое время или длительность(аналогично "человк") hour = rule(normalized("час")) people = rule(normalized("человек")) # слова перед временем начала start_syn = dictionary([ "начало", "старт", "встреча", "переговорную", "переговорку", "пропуск" ]) start_verbs = dictionary([ "начать", "прийти", "заказать", "забронировать", "выделить", "состоится" ]) # слова перед продолжительнотью duration_verbs = dictionary(["займёт", "продлится"]) # слова перед временем конца end_verbs = dictionary(["закончить", "уйдём", "завершим"]) end_syn = dictionary(["конец", "окончание", "завершение"]) # для поиска времени начала, которое выделяется с помощью : или - start_with_separator = or_(rule("начало"), rule("старт"), rule("время"), morph_pipeline(["начало встречи"]), morph_pipeline(["старт встречи"]), morph_pipeline(["время встречи"])) duration_with_separator = or_( rule("продолжительность"), morph_pipeline(["продолжительность встречи"])) end_with_separator = or_(rule("конец"), rule("окончание"), rule("завершение"), morph_pipeline(["конец встречи"]), morph_pipeline(["окончание встречи"]), morph_pipeline(["завершение встречи"])) # относительные указатели на день(относительно сегодняшнего) day_pointer = or_(rule("понедельник"), morph_pipeline(["пн."]), rule("пн"), rule("вторник"), morph_pipeline(["вт."]), rule("вт"), rule("среда"), rule("среду"), morph_pipeline(["ср."]), rule("ср"), rule("четверг"), morph_pipeline(["чт."]), rule("чт"), rule("пятница"), rule("пятницу"), morph_pipeline(["пт."]), rule("пт"), rule("суббота"), rule("субботу"), morph_pipeline(["сб."]), rule("сб"), rule("воскресение"), rule("воскресенье"), morph_pipeline(["вс."]), rule("вс"), rule("завтра"), rule("послезавтра"), rule("сегодня")) # чужие слова self._foreignWords = [ "этаж", "январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь" ] # количественные числительные в числа self._Counts = { "человек": 1, "1": 1, "один": 1, "два": 2, "2": 2, "двое": 2, "вдвоём": 2, "трое": 3, "три": 3, "3": 3, "втроём": 3, "четверо": 4, "четыре": 4, "4": 4, "вчетвером": 4, "5": 5, "пять": 5, "пятеро": 5, "впятером": 5, "6": 6, "шесть": 6, "шестеро": 6, "7": 7, "семь": 7, "семеро": 7, "8": 7, "восемь": 8, "9": 7, "девять": 9, "10": 7, "десять": 10 } # приведение времени к номальной форме self._ToNormalHours = { "08.00": "08:00", "8": "08:00", "восемь": "08:00", "09.00": "09:00", "9": "09:00", "девять": "09:00", "10.00": "10:00", "10": "10:00", "десять": "10:00", "11.00": "11:00", "11": "11:00", "одиннадцать": "11:00", "12.00": "12:00", "12": "12:00", "двенадцать": "12:00", "полдень": "12:00", "13.00": "13:00", "1": "13:00", "13": "13:00", "один": "13:00", "час": "13:00", "часу": "13:00", "14.00": "14:00", "2": "14:00", "14": "14:00", "два": "14:00", "15.00": "15:00", "3": "15:00", "15": "15:00", "три": "15:00", "16.00": "16:00", "4": "16:00", "16": "16:00", "четыре": "16:00", "17.00": "17:00", "5": "17:00", "17": "17:00", "пять": "17:00", "18.00": "18:00", "6": "18:00", "18": "18:00", "шесть": "18:00", "19.00": "19:00", "7": "19:00", "19": "19:00", "семь": "19:00" } # приведение промежутка времени к нормальной форме self._ToNormalDelta = { "1": "01:00", "один": "01:00", "час": "01:00", "1:5": "01:30", "полтора": "01:30", "2": "02:00", "два": "02:00", "3": "03:00", "три": "03:00", "4": "04:00", "четыре": "04:00", "5": "05:00", "пять": "05:00", "6": "06:00", "шесть": "06:00", "7": "7:00", "семь": "07:00" } # правила для времени в формате from time to time self._rulesFromTO = [ # from time to time rule(start_prepositions, or_(hour, rule(or_(hours_t, hours_n))), separator.optional(), minutes_n.optional(), or_(day_periods, hour).optional(), duration_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional()), # чч:мм - чч:мм rule(hours_n, separator, minutes_n, "-", hours_n, separator, minutes_n), # day time to time rule(day_pointer, rule(or_(hours_t, hours_n)), separator.optional(), minutes_n.optional(), or_(day_periods, hour).optional(), duration_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional()) ] # правила для времени в формате from time on time self._rulesFromOn = [ # from time on n hour rule(start_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional(), or_(day_periods, hour).optional(), pr_na, or_(hours_t, hours_n), hour.optional()), # from time on hour rule(start_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional(), or_(day_periods, hour).optional(), pr_na, hour) ] # правила для времени в формате on time from time self._rulesOnFrom = [ # on n hour from time rule(pr_na, or_(hours_t, hours_n), hour, start_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional(), or_(day_periods, hour).optional()), # on hour from time rule(pr_na, hour, start_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional(), or_(day_periods, hour).optional()) ] # правила для времени в формате from time self._rulesFrom = [ # day or start or start verb in time rule(or_(day_pointer, rule(start_syn), rule(start_verbs)), start_prepositions, or_(hours_t, hours_n), separator.optional(), minutes_n.optional()), # start with separator rule(start_with_separator, two_points, or_(rule(hours_t), rule(hours_n)), separator.optional(), minutes_n.optional()), # since time day or hour rule(pr_c, or_(rule(hours_t), rule(hours_n)), separator.optional(), minutes_n.optional(), or_(day_periods, hour)), # since hour rule(pr_c, hour), # on n часов day rule(pr_na, or_(hours_t, hours_n), hour.optional(), day_periods), # on час day rule(pr_na, hour, day_periods) ] # правила для времени окончания и продолжительности self._rulesTo = [ # end or end verb in time rule(or_(end_syn, end_verbs), start_prepositions, or_(rule(hours_t), rule(hours_n), hour), separator.optional(), minutes_n.optional()), # duration verb time-time rule(duration_verbs, hours_n.optional(), dictionary(["."]).optional(), minutes_n.optional(), "-", hours_n.optional(), dictionary(["."]).optional(), hour), # duration verb time rule(duration_verbs, or_(hours_t, hours_n), dictionary(["."]).optional(), minutes_n.optional(), hour), # end with separation rule(end_with_separator, two_points, or_(rule(hours_t), rule(hours_n)), separator.optional(), minutes_n.optional()), # duration with separation rule(duration_with_separator, two_points, or_(rule(hours_t), rule(hours_n)), separator.optional(), minutes_n.optional()) ] # общие правила для начального, конечного времени и продолжительности self._rulesCommon = [ # in time + hour or day period rule(or_(pr_v, pr_vrayone, pr_k), or_(hours_t, hours_n), or_(hour, day_periods)), # on time + day period rule(pr_na, or_(hours_t, hours_n), or_(day_periods)), # in hh:mm rule(pr_v, hours_n, separator, minutes_n), # hh:mm rule(hours_n, two_points, minutes_n, or_(day_periods, hour).optional()), # on n hour rule(pr_na, or_(hours_t, hours_n), hour), # on hour rule(pr_na, hour) ] # правила для количества людей self._rulesCount = [ # coll number rule(coll_numbers_dic), # n people rule(or_(hours_t, hours_n).optional()) ] # правила используемые в повторных запросах self._rulesTime = [ # всевозможные форматы времени rule(or_(rule(hours_t), rule(hours_n), hour), separator.optional(), minutes_n.optional()) ] self._rulesPeriod = [ # всевозможные интервалы времени rule(or_(rule(hours_t), rule(hours_n), hour), dictionary(["."]).optional(), minutes_n.optional()) ] self._rulesCountPeople = [ # количественные числительные rule(coll_numbers_dic), # n человек rule(or_(hours_t, hours_n).optional(), people) ]
TYPE = morph_pipeline([ 'АО', 'ОАО', 'ООО', 'ЗАО', 'ПАО', # TODO Check abbrs # 'ик', # 'нк', # 'хк', # 'ип', # 'чп', # 'ичп', # 'гпф', # 'нпф', # 'бф', # 'спао', # 'сро', 'общество', 'акционерное общество', 'открытое акционерное общество', 'общество с ограниченной ответственностью', 'закрытое акционерное общество', 'публичное акционерное общество', 'агентство', 'компания', 'организация', 'издательство', 'газета', 'концерн' 'фирма', 'завод', 'предприятие', 'корпорация', 'группа', 'группа компаний', 'санаторий', 'объединение', 'бюро', 'подразделение', 'филиал', 'представительство', 'фонд', 'центр', 'нии', 'академия', 'академия наук', 'обсерватория', 'университет', 'институт', 'политех', 'колледж', 'техникум', 'училище', 'школа', 'музей', 'библиотека', 'авиакомпания', 'госкомпания', 'инвесткомпания', 'медиакомпания', 'оффшор-компания', 'радиокомпания', 'телекомпания', 'телерадиокомпания', 'траст-компания', 'фактор-компания', 'холдинг-компания', 'энергокомпания', 'компания-производитель', 'компания-изготовитель', 'компания-заказчик', 'компания-исполнитель', 'компания-посредник', 'группа управляющих компаний', 'агрофирма', 'турфирма', 'юрфирма', 'фирма-производитель', 'фирма-изготовитель', 'фирма-заказчик', 'фирма-исполнитель', 'фирма-посредник', 'авиапредприятие', 'агропредприятие', 'госпредприятие', 'нацпредприятие', 'промпредприятие', 'энергопредприятие', 'авиакорпорация', 'госкорпорация', 'профорганизация', 'стартап', 'нотариальная контора', 'букмекерская контора', 'авиазавод', 'автозавод', 'винзавод', 'подстанция', 'гидроэлектростанция', ])