Извлечение медицинской информации с использованием Python - PullRequest
13 голосов
/ 25 октября 2010

Я медсестра и знаю 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

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

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

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

Ответы [ 4 ]

9 голосов
/ 25 октября 2010

Используется dateutil для анализа даты (например, '11/11 / 2010 - 09:00 am) и 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']}

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

9 голосов
/ 25 октября 2010

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

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

Посмотри, работает ли это для тебя. Может потребоваться некоторая корректировка.

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 голосов
/ 25 октября 2010

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

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':''}
1 голос
/ 25 октября 2010

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

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

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

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

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

...