Извлечение медицинской информации с использованием Python

Я медсестра, и я знаю python, но я не эксперт, просто использовал его для обработки последовательностей ДНК. Мы получили записи в больнице, написанные на человеческих языках, и я должен вставить эти данные в базу данных или файл csv, но они содержат более 5000 строк, и это может быть так сложно. Все данные написаны в согласованном формате, и я покажу вам пример

11/11/2010 - 09:00am : He got nausea, vomiting and died 4 hours later

Мне нужно получить следующие данные

Sex: Male
Symptoms: Nausea
    Vomiting
Death: True
Death Time: 11/11/2010 - 01:00pm

Другой пример

11/11/2010 - 09:00am : She got heart burn, vomiting of blood and died 1 hours later in the operation room

И я получаю

Sex: Female
Symptoms: Heart burn
    Vomiting of blood
Death: True
Death Time: 11/11/2010 - 10:00am

порядок не согласуется с тем, когда я говорю в......., поэтому in является ключевым словом, и весь текст после - это место, пока я не найду другое ключевое слово
В начале он или она определяет пол, получил........ все, что следует, представляет собой группу симптомов, которые я должен разделить в соответствии с разделителем, который может быть запятой, гипной или чем-то другим, но он согласуется с той же строкой < ш > умер..... спустя несколько часов также должен получить, сколько часов, иногда пациент остается жив и разряжен.... и т.д.
Чтобы сказать, что у нас много соглашений, и я думаю, что если я могу подделать текст с помощью ключевых слов и шаблонов, я смогу выполнить эту работу. Поэтому, если вы знаете полезную функцию /modules/tutorial/tool для этого, предпочтительно, в python (если не python, поэтому инструмент gui будет приятным)

Немного информации:

there are a lot of rules to express various medical data but here are few examples
- Start with the same date/time format followed by a space followd by a colon followed by a space followed by He/She followed space followed by rules separated by and
- Rules:
    * got <symptoms>,<symptoms>,....
    * investigations were done <investigation>,<investigation>,<investigation>,......
    * received <drug or procedure>,<drug or procedure>,.....
    * discharged <digit> (hour|hours) later
    * kept under observation
    * died <digit> (hour|hours) later
    * died <digit> (hour|hours) later in <place>
other rules do exist but they follow the same idea

Ответы

Ответ 1

Здесь используется dateutil для анализа даты (например, "11/11/2010 - 09:00 утра" ) и parsedatetime для анализа относительного времени (например, "4 часа спустя" ):

import dateutil.parser as dparser
import parsedatetime.parsedatetime as pdt
import parsedatetime.parsedatetime_consts as pdc
import time
import datetime
import re
import pprint
pdt_parser = pdt.Calendar(pdc.Constants())   
record_time_pat=re.compile(r'^(.+)\s+:')
sex_pat=re.compile(r'\b(he|she)\b',re.IGNORECASE)
death_time_pat=re.compile(r'died\s+(.+hours later).*$',re.IGNORECASE)
symptom_pat=re.compile(r'[,-]')

def parse_record(astr):    
    match=record_time_pat.match(astr)
    if match:
        record_time=dparser.parse(match.group(1))
        astr,_=record_time_pat.subn('',astr,1)
    else: sys.exit('Can not find record time')
    match=sex_pat.search(astr)    
    if match:
        sex=match.group(1)
        sex='Female' if sex.lower().startswith('s') else 'Male'
        astr,_=sex_pat.subn('',astr,1)
    else: sys.exit('Can not find sex')
    match=death_time_pat.search(astr)
    if match:
        death_time,date_type=pdt_parser.parse(match.group(1),record_time)
        if date_type==2:
            death_time=datetime.datetime.fromtimestamp(
                time.mktime(death_time))
        astr,_=death_time_pat.subn('',astr,1)
        is_dead=True
    else:
        death_time=None
        is_dead=False
    astr=astr.replace('and','')    
    symptoms=[s.strip() for s in symptom_pat.split(astr)]
    return {'Record Time': record_time,
            'Sex': sex,
            'Death Time':death_time,
            'Symptoms': symptoms,
            'Death':is_dead}


if __name__=='__main__':
    tests=[('11/11/2010 - 09:00am : He got nausea, vomiting and died 4 hours later',
            {'Sex':'Male',
             'Symptoms':['got nausea', 'vomiting'],
             'Death':True,
             'Death Time':datetime.datetime(2010, 11, 11, 13, 0),
             'Record Time':datetime.datetime(2010, 11, 11, 9, 0)}),
           ('11/11/2010 - 09:00am : She got heart burn, vomiting of blood and died 1 hours later in the operation room',
           {'Sex':'Female',
             'Symptoms':['got heart burn', 'vomiting of blood'],
             'Death':True,
             'Death Time':datetime.datetime(2010, 11, 11, 10, 0),
             'Record Time':datetime.datetime(2010, 11, 11, 9, 0)})
           ]

    for record,answer in tests:
        result=parse_record(record)
        pprint.pprint(result)
        assert result==answer
        print

дает:

{'Death': True,
 'Death Time': datetime.datetime(2010, 11, 11, 13, 0),
 'Record Time': datetime.datetime(2010, 11, 11, 9, 0),
 'Sex': 'Male',
 'Symptoms': ['got nausea', 'vomiting']}

{'Death': True,
 'Death Time': datetime.datetime(2010, 11, 11, 10, 0),
 'Record Time': datetime.datetime(2010, 11, 11, 9, 0),
 'Sex': 'Female',
 'Symptoms': ['got heart burn', 'vomiting of blood']}

Примечание. Будьте осторожны при проведении парсинга. "8/9/2010" означает 9 августа или 8 сентября? Используют ли все хранители записей одно и то же соглашение? Если вы решите использовать dateutil (и я действительно считаю, что лучший вариант, если строка даты не жестко структурирована), обязательно прочитайте раздел "Формат приоритета" в dateutil, чтобы вы могли (надеюсь) правильно решить "8/9/2010". Если вы не можете гарантировать, что все хранители записей используют одно и то же соглашение для указания дат, тогда результаты этого script будут проверяться вручную. Это может быть разумным в любом случае.

Ответ 2

Вот несколько возможных способов решения этой проблемы -

  • Использование регулярных выражений. Определите их в соответствии с шаблонами в тексте. Сопоставьте выражения, извлеките шаблон и повторите все записи. Этот подход требует хорошего понимания формата, в котором находятся данные и, конечно же, регулярных выражений:)
  • Манипуляция строк. Этот подход относительно прост. Опять же нужно хорошее понимание формата, в котором данные. Это то, что я сделал ниже.
  • Машинное обучение. Вы можете определить все правила и подготовить модель к этим правилам. После этого модель пытается извлечь данные, используя предоставленные вами правила. Это гораздо более общий подход, чем первые два. Также самый сложный для реализации.

Посмотрите, работает ли это для вас. Возможно, потребуются некоторые корректировки.

new_file = open('parsed_file', 'w')
for rec in open("your_csv_file"):
    tmp = rec.split(' : ')
    date = tmp[0]
    reason = tmp[1]

    if reason[:2] == 'He':
        sex = 'Male'
        symptoms = reason.split(' and ')[0].split('He got ')[1]
    else:
        sex = 'Female'
        symptoms = reason.split(' and ')[0].split('She got ')[1]
    symptoms = [i.strip() for i in symptoms.split(',')]
    symptoms = '\n'.join(symptoms)
    if 'died' in rec:
        died = 'True'
    else:
        died = 'False'
    new_file.write("Sex: %s\nSymptoms: %s\nDeath: %s\nDeath Time: %s\n\n" % (sex, symptoms, died, date))

Запись Ech разделена на новую строку \n, и поскольку вы не указали, что одна запись пациента состоит из двух новых строк, разделенных \n\n от другого.

ПОЗЖЕ: @Нажмите, что вы в итоге сделали? Просто любопытно.

Ответ 3

Может быть, это тоже поможет вам, оно не проверено

import collections
import datetime
import re

retrieved_data = []

Data = collections.namedtuple('Patient', 'Sex, Symptoms, Death, Death_Time')
dict_data = {'Death':'',
             'Death_Time':'',
             'Sex' :'',
             'Symptoms':''}


with open('data.txt') as f:
     for line in iter(f.readline, ""):

         date, text = line.split(" : ")
         if 'died' in text:
             dict_data['Death'] = True
             dict_data['Death_Time'] = datetime.datetime.strptime(date, 
                                                                 '%d/%m/%Y - %I:%M%p')
             hours = re.findall('[\d]+', datetime.text)
             if hours:
                 dict_data['Death_Time'] += datetime.timedelta(hours=int(hours[0]))
         if 'she' in text:
            dict_data['Sex'] = 'Female'
         else:
            dict_data['Sex'] = 'Male'

         symptoms = text[text.index('got'):text.index('and')].split(',')

         dict_data['Symptoms'] = '\n'.join(symptoms) 

         retrieved_data.append(Data(**dict_data))

         # EDIT : Reset the data dictionary.
         dict_data = {'Death':'',
             'Death_Time':'',
             'Sex' :'',
             'Symptoms':''}

Ответ 4

Было бы относительно легко сделать большую часть обработки в отношении пола, даты/времени и т.д., как те, которые были показаны до того, как вы показали, поскольку вы действительно можете просто определить набор ключевых слов, которые будут указывать на эти вещи и использовать эти ключевые слова.

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

Вот выбор, который вы должны сделать: обрабатывает ли эти данные действительно достаточную работу, чтобы потратить дни, написав программу, чтобы сделать это для меня? Если это так, то вы должны изучить обработку естественного языка (или машинное обучение, как сказал кто-то, кто передо мной). Я слышал довольно хорошие вещи о nltk, набор инструментов для естественного языка для Python. Если формат такой же последовательный, как вы говорите, обработка естественного языка может быть не слишком сложной.

Но, если вы не хотите тратить время и силы на решение действительно сложной проблемы CS (и, поверьте, обработка естественного языка), тогда вы должны выполнить большую часть обработки в Python, анализируя даты, местоимные местоимения и т.д. и входить в более жесткие части вручную (например, симптомы).

Опять же, это зависит от того, считаете ли вы, что программное или ручное решение займет меньше времени в конечном итоге.