nltk StanfordNERTagger:如何在没有大写的情况下获得专有名词

时间:2015-12-23 15:47:03

标签: python nlp nltk stanford-nlp pos-tagger

我正在尝试使用StanfordNERTagger和nltk从一段文本中提取关键字。

docText="John Donk works for POI. Brian Jones wants to meet with Xyz Corp. for measuring POI's Short Term performance Metrics."

words = re.split("\W+",docText) 

stops = set(stopwords.words("english"))

    #remove stop words from the list
words = [w for w in words if w not in stops and len(w) > 2]

str = " ".join(words)
print str
stn = StanfordNERTagger('english.all.3class.distsim.crf.ser.gz') 
stp = StanfordPOSTagger('english-bidirectional-distsim.tagger') 
stanfordPosTagList=[word for word,pos in stp.tag(str.split()) if pos == 'NNP']

print "Stanford POS Tagged"
print stanfordPosTagList
tagged = stn.tag(stanfordPosTagList)
print tagged

这给了我

John Donk works POI Brian Jones wants meet Xyz Corp measuring POI Short Term performance Metrics
Stanford POS Tagged
[u'John', u'Donk', u'POI', u'Brian', u'Jones', u'Xyz', u'Corp', u'POI', u'Short', u'Term']
[(u'John', u'PERSON'), (u'Donk', u'PERSON'), (u'POI', u'ORGANIZATION'), (u'Brian', u'ORGANIZATION'), (u'Jones', u'ORGANIZATION'), (u'Xyz', u'ORGANIZATION'), (u'Corp', u'ORGANIZATION'), (u'POI', u'O'), (u'Short', u'O'), (u'Term', u'O')]

很明显,ShortTerm之类的内容被标记为NNP。我拥有的数据包含许多此类实例,其中NNP字词大写。这可能是由于拼写错误或者可能是标题。我对此没有多少控制权。

我如何解析或清理数据,以便我可以检测到非NNP项,即使它可能是大写的? 我不希望将ShortTerm等字词归类为NNP

另外,不确定为什么John Donk被人捕获但Brian Jones没有。可能是由于我的数据中其他大写的非NNP?这会对StanfordNERTagger如何对待其他一切产生影响吗?

更新,一种可能的解决方案

这是我打算做的事情

  1. 取出每个单词并转换为小写
  2. 标记小写字词
  3. 如果代码为NNP,则我们知道原始字词也必须是NNP
  4. 如果没有,则原始单词错误大写
  5. 这是我试图做的事情

    str = " ".join(words)
    print str
    stp = StanfordPOSTagger('english-bidirectional-distsim.tagger') 
    for word in str.split():
        wl = word.lower()
        print wl
        w,pos = stp.tag(wl)
        print pos
        if pos=="NNP":
            print "Got NNP"
            print w
    

    但是这给了我错误

    John Donk works POI Jones wants meet Xyz Corp measuring POI short term performance metrics
    john
    Traceback (most recent call last):
      File "X:\crp.py", line 37, in <module>
        w,pos = stp.tag(wl)
    ValueError: too many values to unpack
    

    我尝试过多种方法,但总会出现一些错误。 如何标记单个字词?

    我不想将整个字符串转换为小写,然后是Tag。如果我这样做,StanfordPOSTagger将返回一个空字符串

2 个答案:

答案 0 :(得分:5)

首先,请参阅另一个问题,设置从命令行或python调用Stanford CoreNLP:nltk : How to prevent stemming of proper nouns

对于正确的句子,我们看到NER正常工作:

>>> from corenlp import StanfordCoreNLP
>>> nlp = StanfordCoreNLP('http://localhost:9000')
>>> text = ('John Donk works POI Jones wants meet Xyz Corp measuring POI short term performance metrics. '
... 'john donk works poi jones wants meet xyz corp measuring poi short term performance metrics')
>>> output = nlp.annotate(text, properties={'annotators': 'tokenize,ssplit,pos,ner',  'outputFormat': 'json'})
>>> annotated_sent0 = output['sentences'][0]
>>> annotated_sent1 = output['sentences'][1]
>>> for token in annotated_sent0['tokens']:
...     print token['word'], token['lemma'], token['pos'], token['ner']
... 
John John NNP PERSON
Donk Donk NNP PERSON
works work VBZ O
POI POI NNP ORGANIZATION
Jones Jones NNP ORGANIZATION
wants want VBZ O
meet meet VB O
Xyz Xyz NNP ORGANIZATION
Corp Corp NNP ORGANIZATION
measuring measure VBG O
POI poi NN O
short short JJ O
term term NN O
performance performance NN O
metrics metric NNS O
. . . O

对于降低的句子,你不会得到NNP的POS标签或任何NER标签:

>>> for token in annotated_sent1['tokens']:
...     print token['word'], token['lemma'], token['pos'], token['ner']
... 
john john NN O
donk donk JJ O
works work NNS O
poi poi VBP O
jones jone NNS O
wants want VBZ O
meet meet VB O
xyz xyz NN O
corp corp NN O
measuring measure VBG O
poi poi NN O
short short JJ O
term term NN O
performance performance NN O
metrics metric NNS O

所以你问题的问题应该是:

  • 您的NLP应用程序的最终目标是什么?
  • 为什么您的输入较低?是你在做什么还是如何提供数据?

在回答完这些问题之后,你可以继续决定你真正想用NER标签做什么,即

  • 如果输入内容较低且由于您构建NLP工具链的方式,那么

    • 不要这样做!!! 在普通文本上执行NER而不会产生您的扭曲。这是因为NER是在正常文本上训练的,所以它不会在正常文本的背景下真正起作用。
    • 同时尝试不要混合使用不同套件的NLP工具,它们通常不会很好用,尤其是在你的NLP工具链的最后。
  • 如果输入内容较低,因为原始数据是的原因,那么:

  • 如果输入有错误的套管,例如“有些大而小但不是全部是正确的名词,那么

    • 尝试真正的解决方案。

答案 1 :(得分:0)

首先,您不应在程序中使用预定义关键字作为变量名称。避免使用str作为变量名。而是使用newstring或其他任何东西。

在您的更新中,您将每个小写字词传递给POS标记器。 tag()方法拆分传递给它的每个字符串,并为每个字符提供POS标记。

所以我建议您将list而不是单词传递给tag()方法。 该列表一次只包含一个单词。

您可以尝试:w = stp.tag([wl]) w将是包含两个[w1,POS]

项的列表

通过这种方式,您可以标记单个字

但在这种情况下,它会将john的POS标记设为NN