【问题标题】:how to speed up NE recognition with stanford NER with python nltk如何使用 stanford NER 和 python nltk 加速 NE 识别
【发布时间】:2016-02-18 07:53:53
【问题描述】:

首先我将文件内容标记为句子,然后对每个句子调用 Stanford NER。但是这个过程真的很慢。我知道如果我在整个文件内容上调用它会更快,但是我在每个句子上调用它,因为我想在 NE 识别之前和之后索引每个句子。

st = NERTagger('stanford-ner/classifiers/english.all.3class.distsim.crf.ser.gz', 'stanford-ner/stanford-ner.jar')
for filename in filelist:
    sentences = sent_tokenize(filecontent) #break file content into sentences
    for j,sent in enumerate(sentences): 
        words = word_tokenize(sent) #tokenize sentences into words
        ne_tags = st.tag(words) #get tagged NEs from Stanford NER

这可能是因为每个句子都调用了st.tag(),但是有什么办法让它跑得更快?

编辑

我想单独标记句子的原因是我想将句子写入文件(如句子索引),以便在稍后阶段给定 ne 标记的句子,我可以得到未处理的句子(我也是在这里做词形还原)

文件格式:

(sent_number, orig_sentence, NE_and_lemmatized_sentence)

【问题讨论】:

    标签: python nlp nltk stanford-nlp named-entity-recognition


    【解决方案1】:

    StanfordNERTagger,有tag_sents()函数,见https://github.com/nltk/nltk/blob/develop/nltk/tag/stanford.py#L68

    >>> st = NERTagger('stanford-ner/classifiers/english.all.3class.distsim.crf.ser.gz', 'stanford-ner/stanford-ner.jar')
    >>> tokenized_sents = [[word_tokenize(sent) for sent in sent_tokenize(filecontent)] for filename in filelist]
    >>> st.tag_sents(tokenized_sents)
    

    【讨论】:

    • 我不认为这会做我想要的,因为它会输出标记的句子。我想要的是原始句子和 ne 标记句子对,我将其写入以下格式的文件:
    • (sent_no, orig_sent, tagged_sent) 例如,0,皇家妇女医院的新医生,royal_womens_hospital 的新医生。我认为您的回答不允许我这样做?
    • 只遍历只包含输入语句的文件内容。在此之前进行一些数据清理,代码就可以工作了。否则,您可以发布输入文件的示例。文件格式没有帮助,一个样本可以帮助我们更好地理解这个问题 =)
    • 我刚刚发现了一个奇怪的情况,在处理我的数据时这不起作用。请看看这篇文章? stackoverflow.com/questions/33755092/…
    【解决方案2】:

    您可以使用 stanford ner 服务器。 速度会快很多。

    安装sner

    pip install sner
    

    运行服务器

    cd your_stanford_ner_dir
    java -Djava.ext.dirs=./lib -cp stanford-ner.jar edu.stanford.nlp.ie.NERServer -port 9199 -loadClassifier ./classifiers/english.all.3class.distsim.crf.ser.gz

    from sner import Ner
    
    test_string = "Alice went to the Museum of Natural History."
    tagger = Ner(host='localhost',port=9199)
    print(tagger.get_entities(test_string))

    这段代码结果是

    [('Alice', 'PERSON'),
     ('went', 'O'),
     ('to', 'O'),
     ('the', 'O'),
     ('Museum', 'ORGANIZATION'),
     ('of', 'ORGANIZATION'),
     ('Natural', 'ORGANIZATION'),
     ('History', 'ORGANIZATION'),
     ('.', 'O')]

    更多细节看https://github.com/caihaoyu/sner

    【讨论】:

    • 真的快多了! :)
    • 谢谢,它成功了。是否可以部署在任何云服务上并使用它?
    • 速度很快,但有时会漏掉一些 PERSON 实体。
    【解决方案3】:

    首先从这里下载Stanford CoreNLP 3.5.2:http://nlp.stanford.edu/software/corenlp.shtml

    假设您将下载放在 /User/username/stanford-corenlp-full-2015-04-20

    此 Python 代码将运行管道:

    stanford_distribution_dir = "/User/username/stanford-corenlp-full-2015-04-20"
    list_of_sentences_path = "/Users/username/list_of_sentences.txt"
    stanford_command = "cd %s ; java -Xmx2g -cp \"*\" edu.stanford.nlp.pipeline.StanfordCoreNLP -annotators tokenize,ssplit,pos,lemma,ner -ssplit.eolonly -filelist %s -outputFormat json" % (stanford_distribution_dir, list_of_sentences_path)
    os.system(stanford_command)
    

    以下是一些用于加载 .json 文件的示例 Python 代码以供参考:

    import json
    sample_json = json.loads(file("sample_file.txt.json").read()
    

    此时,sample_json 将是一个很好的字典,其中包含文件中的所有句子。

    for sentence in sample_json["sentences"]:
      tokens = []
      ner_tags = []
      for token in sentence["tokens"]:
        tokens.append(token["word"])
        ner_tags.append(token["ner"])
      print (tokens, ner_tags)
    

    list_of_sentences.txt 应该是带有句子的文件列表,例如:

    input_file_1.txt
    input_file_2.txt
    ...
    input_file_100.txt
    

    因此,一旦运行 Java 命令,input_file.txt(每行应该有一个句子)将生成 input_file.txt.json,并且 .json 文件将具有 NER 标记。您可以为每个输入文件加载 .json 并轻松获取(句子,ner 标签序列)对。如果您更喜欢“文本”作为替代输出格式,您可以进行试验。但是“json”会创建一个不错的 .json 文件,您可以使用 json.loads(...) 加载该文件,然后您将拥有一个不错的字典,您可以使用它来访问句子和注释。

    这样,您只需为所有文件加载一次管道。

    【讨论】:

    • 听起来不错!但是创建输入的一些工作将在以后尝试!谢谢
    • 感谢您能帮我解决这个问题吗? stackoverflow.com/questions/33755092/…
    • 我在答案中添加了一些关于在 Python 中加载 json 的信息。
    【解决方案4】:

    在尝试了几个选项后,我喜欢Stanza。它由斯坦福开发,实现起来非常简单,我不必自己弄清楚如何正确启动服务器,它极大地提高了我的程序速度。它实现了 18 种不同的对象分类。

    我在搜索 the documentation 时找到了 Stanza。

    下载: pip install stanza

    然后在 Python 中:

    import stanza
    stanza.download('en') # download English model
    nlp = stanza.Pipeline('en') # initialize English neural pipeline
    doc = nlp("My name is John Doe.") # run annotation over a sentence or multiple sentences
    

    如果您只需要特定工具 (NER),您可以使用 processors 指定为: nlp = stanza.Pipeline('en',processors='tokenize,ner')

    对于类似于 OP 产生的输出:

    classified_text = [(token.text,token.ner) for i, sentence in enumerate(doc.sentences) for token in sentence.tokens]
    print(classified_text)
    [('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'B-PERSON'), ('Doe', 'E-PERSON')]
    

    但要生成仅包含可识别实体的单词的列表:

    classified_text = [(ent.text,ent.type) for ent in doc.ents]
    [('John Doe', 'PERSON')]
    

    它产生了一些我非常喜欢的功能:

    1. 您可以使用doc.sentences 访问每个句子。
    2. 不是将每个单词分类为单独的人实体,而是将 John Doe 组合成一个“PERSON”对象。
    3. 如果您确实需要每个单独的词,您可以提取这些词并识别它是对象的哪个部分(“B”表示对象中的第一个词,“I”表示中间词,“E”表示对象中的最后一个单词)

    【讨论】:

      猜你喜欢
      • 2015-12-25
      • 1970-01-01
      • 1970-01-01
      • 2014-06-12
      • 2013-11-10
      • 1970-01-01
      • 1970-01-01
      • 2015-06-17
      • 1970-01-01
      相关资源
      最近更新 更多