使用Python提取医疗信息

时间:2010-10-25 02:31:03

标签: python parsing machine-learning nlp information-extraction

我是一名护士,我知道python,但我不是专家,只是用它来处理DNA序列 我们得到了用人类语言编写的医院记录,我应该将这些数据插入到数据库或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是一个关键字并且之后的所有文本都是一个地方,直到我找到另一个关键字时,订单不一致 在开始他或她确定性,得到........无论后面是一组症状,我应该根据分隔符分割,可以是逗号,炒作或其他什么,但它是同一行的一致<登记/> 死了......几个小时后也应该得到多少小时,有时患者还活着并出院......等等 这就是说我们有很多约定,我认为如果我能用关键字和模式对文本进行标记,我可以完成工作。所以,如果你知道一个有用的函数/模块/教程/工具,最好在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

4 个答案:

答案 0 :(得分:9)

以下是一些可以解决此问题的方法 -

  1. 使用正则表达式 - 根据文本中的模式定义它们。匹配表达式,提取模式,然后重复所有记录。这种方法需要很好地理解数据的格式。当然是正则表达式:)
  2. 字符串操作 - 这种方法相对简单。人们需要很好地理解数据的格式。这就是我在下面所做的。
  3. 机器学习 - 您可以定义所有规则&amp;训练这些规则的模型。在此之后,模型尝试使用您提供的规则提取数据。这比前两种方法更通用。也是最难实施的。
  4. 看看这对你有用吗?可能需要一些调整。

    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&amp;因为你没有提到一个患者记录,所以2个新行与另一个分开\n\n

    以后: @Nurse你最终做了什么?好奇。

答案 1 :(得分:9)

这使用dateutil来解析日期(例如'11 / 11/2010 - 09:00 am'),parsedatetime来解析相对时间(例如'4小时后'):< / p>

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”是指8月9日还是9月8日?所有记录员都使用相同的约定吗?如果你选择使用dateutil(我真的认为如果日期字符串没有严格的结构,那么这是最好的选择)请务必阅读dateutil documentation中关于“格式优先级”的部分,这样你就可以(希望)解决' 2010年8月9日'正确。 如果您不能保证所有记录管理员使用相同的约定来指定日期,那么将手动检查此脚本的结果。无论如何,这可能是明智的。

答案 2 :(得分: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':''}

答案 3 :(得分:1)

关于性别,日期/时间等的大部分处理相对容易,就像你展示之前那样,因为你可以真正定义一组关键字来表明这些事情并使用那些关键词。

然而,处理症状的问题有点不同,因为代表症状的关键词的确定列表将很难并且很可能是不可能的。

这是你必须做出的选择:处理这些数据真的代表了足够的工作来花费数天时间编写程序来为我做这些吗?如果是这种情况,那么你应该研究自然语言处理(或机器学习,就像我之前所说的那样)。我听说过nltk非常好的东西,这是一个Python的自然语言工具包。如果格式与您所说的一致,则自然语言处理可能不会太困难。

但是,如果你不愿意花费时间和精力来解决一个真正困难的CS问题(相信我,自然语言处理),那么你应该通过解析日期来完成Python中的大部分处理,性别特定的代词等,并用手进入更强硬的部分(例如症状)。

同样,这取决于您是否认为程序化或手动解决方案从长远来看会花费更少的时间。