Python NLTK命名实体

时间:2015-03-29 05:16:01

标签: python nltk

我是NLTK的新手。我有一个文本文件,其中包含有关药物及其副作用的文本。所以我需要提取药物名称和副作用的名称。

对此我写了这段代码

import sys, re, nltk, pprint
x = "Allegra (fexofenadine hydrochloride) is an antihistamine used to 
     treat allergic symptoms of seasonal allergic rhinitis (sneezing, 
     runny nose, itchy or watery eyes), and urticaria (hives). Allegra is 
     available as a generic drug termed fexofenadine hydrochloride. 
     Allegra is used in adults and children (2 years and older for 
     allergies, 6 months and older for hives) for the control and 
     reduction of the above symptoms. Some common side effects of Allegra
     include GI symptoms of nausea or diarrhea, muscle or back discomfort
     or pain, sleepiness, and menstrual cramps."
data = nltk.word_tokenize(x)
tagged = nltk.pos_tag(data)
namedEnt = nltk.ne_chunk(tagged, binary=True)

我得到一个非常复杂的输出

Tree('S', [Tree('NE', [('Allegra', 'NNP')]), ('(', ':'), 
    ('fexofenadine', 'NN'), ('hydrochloride', 'NN'), (')', ':'), 
    ('is', 'VBZ'), ('an', 'DT'), ('antihistamine', 'NN'), 
    ('used', 'VBN'), ('to', 'TO'), ('treat', 'VB'), ('allergic', 'JJ'), 
    ('symptoms', 'NNS'), ('of', 'IN'), ('seasonal', 'JJ'), 
    ('allergic', 'NN'), ('rhinitis', 'NNS'), ('(', ':'), 
    ('sneezing', 'VBG'), (',', ','), ('runny', 'JJ'), ('nose', 'NN'), 
    (',', ','), ('itchy', 'JJ'), ('or', 'CC'), ('watery', 'NN'), 
    ('eyes', 'NNS'), (')', ':'), (',', ','), ('and', 'CC'), 
    ('urticaria', 'VB'), ('(', ':'), ('hives', 'NNS'), (')', 'VBP'),
    ('.', '.'), ('Allegra', 'NNP'), ('is', 'VBZ'), ('available', 'JJ'), 
    ('as', 'IN'), ('a', 'DT'), ('generic', 'JJ'), ('drug', 'NN'), 
    ('termed', 'VBD'), ('fexofenadine', 'NN'), ('hydrochloride', 'NN'), 
    ('.', '.'), ('Allegra', 'NNP'), ('is', 'VBZ'), ('used', 'VBN'), 
    ('in', 'IN'), ('adults', 'NNS'), ('and', 'CC'), ('children', 'NNS'), 
    ('(', ':'), ('2', 'CD'), ('years', 'NNS'), ('and', 'CC'), 
    ('older', 'JJR'), ('for', 'IN'), ('allergies', 'NNS'), (',', ','), 
    ('6', 'CD'), ('months', 'NNS'), ('and', 'CC'), ('older', 'JJR'), 
    ('for', 'IN'), ('hives', 'NNS'), (')', ':'), ('for', 'IN'), 
    ('the', 'DT'), ('control', 'NN'), ('and', 'CC'), ('reduction', 'NN'), 
    ('of', 'IN'), ('the', 'DT'), ('above', 'JJ'), ('symptoms', 'NNS'), 
    ('.', '.'), ('Some', 'DT'), ('common', 'JJ'), ('side', 'NN'), 
    ('effects', 'NNS'), ('of', 'IN'), ('Allegra', 'NNP'), 
    ('include', 'VBP'), ('GI', 'NNP'), ('symptoms', 'NNS'), ('of', 'IN'), 
    ('nausea', 'NN'), ('or', 'CC'), ('diarrhea', 'NN'), (',', ','), 
    ('muscle', 'NN'), ('or', 'CC'), ('back', 'RB'), ('discomfort', 'JJ'), 
    ('or', 'CC'), ('pain', 'NN'), (',', ','), ('sleepiness', 'NN'), 
    (',', ','), ('and', 'CC'), ('menstrual', 'JJ'), ('cramps', 'NNS'), 
    ('.', '.')])

现在这真令人困惑,因为我希望得到的是

  1. Allegra的
  2. 恶心
  3. 腹泻,
  4. 肌肉或背部不适或疼痛,
  5. 困倦,
  6. 月经来潮
  7. 那么我如何缩小到我要查找的数据呢?

2 个答案:

答案 0 :(得分:1)

好像你在这里问了两个问题。首先,NLTK为您提供了一棵树,但您只对命名实体感兴趣。您可以这样选择它们:

for subtree in t.subtrees(filter=lambda x: x.label() == 'NE'):
    print subtree.leaves()

然而,第二,此输出显示Python仅确定了您正在寻找的命名实体之一。这意味着您必须找到除标准ne_chunk之外的其他方式来获得答案。这里有很多选择。例如,您可以在自己的数据上训练一个新的命名实体标记器,其中所有适当的单词都标记为命名实体。如果您没有任何标记数据,则可以使用WordNet之类的资源查找每个单词或短语的语义类型,并仅保留那些属于“症状”的单词。或者,您可以使用语义向量(例如由Google word2vec生成的语义向量)来识别您的句子中与参考词(如“疾病”)足够相似的所有单词。

答案 1 :(得分:1)

作为一个有点临时的解决方案大纲,我建议添加noun phrase extraction和一个简单的启发式方法,只从第一个句子开始提取症状候选词,其中包含“副作用”(或者可能是一小组近似同义词) )。这源于观察到药物声明倾向于具有相当严格的结构,首先描述药物的预期用途,然后描述其可能的副作用和其他警告。

从症状候选者中,你可以保留一个常见症状目录,然后假设夹在两个已知症状之间的任何东西也是一种症状,因为它们往往只是一个逗号分隔的名词短语列表,可能是两者之间的连接其中一些。