webentwicklung-frage-antwort-db.com.de

Verbesserung der Extraktion menschlicher Namen mit nltk

Ich versuche, menschliche Namen aus Text zu extrahieren. 

Hat jemand eine Methode, die sie empfehlen würden?

Ich habe es ausprobiert (Code ist unten): Ich benutze nltk, um alles zu finden, was als Person markiert ist, und generiert dann eine Liste aller NNP-Teile dieser Person. Ich überspringe Personen, bei denen es nur einen NNP gibt, der es vermeidet, einen einsamen Nachnamen zu ergreifen.

Ich bekomme anständige Ergebnisse, habe mich aber gefragt, ob es bessere Wege gibt, dieses Problem zu lösen.

Code:

import nltk
from nameparser.parser import HumanName

def get_human_names(text):
    tokens = nltk.tokenize.Word_tokenize(text)
    pos = nltk.pos_tag(tokens)
    sentt = nltk.ne_chunk(pos, binary = False)
    person_list = []
    person = []
    name = ""
    for subtree in sentt.subtrees(filter=lambda t: t.node == 'PERSON'):
        for leaf in subtree.leaves():
            person.append(leaf[0])
        if len(person) > 1: #avoid grabbing lone surnames
            for part in person:
                name += part + ' '
            if name[:-1] not in person_list:
                person_list.append(name[:-1])
            name = ''
        person = []

    return (person_list)

text = """
Some economists have responded positively to Bitcoin, including 
Francois R. Velde, senior economist of the Federal Reserve in Chicago 
who described it as "an elegant solution to the problem of creating a 
digital currency." In November 2013 Richard Branson announced that 
Virgin Galactic would accept Bitcoin as payment, saying that he had invested 
in Bitcoin and found it "fascinating how a whole new global currency 
has been created", encouraging others to also invest in Bitcoin.
Other economists commenting on Bitcoin have been critical. 
Economist Paul Krugman has suggested that the structure of the currency 
incentivizes hoarding and that its value derives from the expectation that 
others will accept it as payment. Economist Larry Summers has expressed 
a "wait and see" attitude when it comes to Bitcoin. Nick Colas, a market 
strategist for ConvergEx Group, has remarked on the effect of increasing 
use of Bitcoin and its restricted supply, noting, "When incremental 
adoption meets relatively fixed supply, it should be no surprise that 
prices go up. And that’s exactly what is happening to BTC prices."
"""

names = get_human_names(text)
print "LAST, FIRST"
for name in names: 
    last_first = HumanName(name).last + ', ' + HumanName(name).first
        print last_first

Ausgabe:

LAST, FIRST
Velde, Francois
Branson, Richard
Galactic, Virgin
Krugman, Paul
Summers, Larry
Colas, Nick

Abgesehen von Virgin Galactic ist dies alles gültige Ausgabe. Zu wissen, dass Virgin Galactic kein menschlicher Name im Kontext dieses Artikels ist, ist natürlich der schwierige (möglicherweise unmögliche) Teil.

37
emh

Muss mit dem Vorschlag einverstanden sein, dass "make my code better" für diese Site nicht gut geeignet ist, aber ich kann Ihnen einen Weg geben, auf dem Sie versuchen können, in zu graben.

Werfen Sie einen Blick auf Stanford Named Entity Recognizer (NER) . Die Bindung wurde in NLTK 2.0 integriert, Sie müssen jedoch einige Kerndateien herunterladen. Hier ist script das kann das alles für Sie tun.

Ich habe dieses Skript geschrieben:

import nltk
from nltk.tag.stanford import NERTagger
st = NERTagger('stanford-ner/all.3class.distsim.crf.ser.gz', 'stanford-ner/stanford-ner.jar')
text = """YOUR TEXT GOES HERE"""

for sent in nltk.sent_tokenize(text):
    tokens = nltk.tokenize.Word_tokenize(sent)
    tags = st.tag(tokens)
    for tag in tags:
        if tag[1]=='PERSON': print tag

und bekam nicht so schlechte Ausgabe:

('Francois', 'PERSON') ('R.', 'PERSON') ('Velde', 'PERSON') ('Richard', 'PERSON') ('Branson', 'PERSON') ('Jungfrau', 'PERSON') ('Galaktik', 'PERSON') ('Bitcoin', 'PERSON') ('Bitcoin', 'PERSON') ('Paul', 'PERSON') ('Krugman', 'PERSON') ('Larry', 'PERSON') ('Summers', 'PERSON') ('Bitcoin', 'PERSON') ('Nick', 'PERSON') ('Colas', 'PERSON')

Hoffe das ist hilfreich.

19
troyane

Für jeden, der etwas anderes sucht, fand ich diesen Artikel nützlich: http://timmcnamara.co.nz/post/2650550090/extracting-names-with-6-lines-of-python-code

>>> import nltk
>>> def extract_entities(text):
...     for sent in nltk.sent_tokenize(text):
...         for chunk in nltk.ne_chunk(nltk.pos_tag(nltk.Word_tokenize(sent))):
...             if hasattr(chunk, 'node'):
...                 print chunk.node, ' '.join(c[0] for c in chunk.leaves())
...
6
Curtis Mattoon

Sie können versuchen, die gefundenen Namen aufzulösen und zu überprüfen, ob Sie sie in einer Datenbank wie z. B. freebase.com finden können. Laden Sie die Daten lokal ab und fragen Sie sie ab (in RDF), oder verwenden Sie die API von Google: https://developers.google.com/freebase/v1/getting-started . Die meisten großen Unternehmen, geografischen Standorte usw. (die von Ihrem Snippet erfasst würden) könnten dann basierend auf den Freebase-Daten verworfen werden. 

5

Spacy kann eine gute Alternative zum Abrufen von Namen aus einem Text sein.

https://spacy.io/usage/training#ner

4
neel

Ich wollte eigentlich nur den Personennamen extrahieren, also dachte ich daran, alle Namen, die als Ausgabe ausgegeben werden, gegen wordnet (eine große lexikalische Datenbank von Englisch) zu überprüfen. Weitere Informationen zu Wordnet finden Sie hier: http: //www.nltk.org/howto/wordnet.html

import nltk
from nameparser.parser import HumanName
from nltk.corpus import wordnet

person_names=person_list
person_list = []
def get_human_names(text):
    tokens = nltk.tokenize.Word_tokenize(text)
    pos = nltk.pos_tag(tokens)
    sentt = nltk.ne_chunk(pos, binary = False)

    person = []
    name = ""
    for subtree in sentt.subtrees(filter=lambda t: t.label() == 'PERSON'):
        for leaf in subtree.leaves():
            person.append(leaf[0])
        if len(person) > 1: #avoid grabbing lone surnames
            for part in person:
                name += part + ' '
            if name[:-1] not in person_list:
                person_list.append(name[:-1])
            name = ''
        person = []
#     print (person_list)

text = """

Some economists have responded positively to Bitcoin, including 
Francois R. Velde, senior economist of the Federal Reserve in Chicago 
who described it as "an elegant solution to the problem of creating a 
digital currency." In November 2013 Richard Branson announced that 
Virgin Galactic would accept Bitcoin as payment, saying that he had invested 
in Bitcoin and found it "fascinating how a whole new global currency 
has been created", encouraging others to also invest in Bitcoin.
Other economists commenting on Bitcoin have been critical. 
Economist Paul Krugman has suggested that the structure of the currency 
incentivizes hoarding and that its value derives from the expectation that 
others will accept it as payment. Economist Larry Summers has expressed 
a "wait and see" attitude when it comes to Bitcoin. Nick Colas, a market 
strategist for ConvergEx Group, has remarked on the effect of increasing 
use of Bitcoin and its restricted supply, noting, "When incremental 
adoption meets relatively fixed supply, it should be no surprise that 
prices go up. And that’s exactly what is happening to BTC prices."
"""

names = get_human_names(text)
for person in person_list:
    person_split = person.split(" ")
    for name in person_split:
        if wordnet.synsets(name):
            if(name in person):
                person_names.remove(person)
                break

print(person_names)

AUSGABE

['Francois R. Velde', 'Richard Branson', 'Economist Paul Krugman', 'Nick Colas']

Abgesehen von Larry Summers sind alle Namen korrekt und das ist auf den Nachnamen "Summers" zurückzuführen. 

2

Die Antwort von @trojane hat für mich nicht ganz funktioniert, hat mir aber sehr geholfen.

Vorkenntnisse

Erstellen Sie einen Ordner stanford-ner und laden Sie die folgenden beiden Dateien herunter:

Skript

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import nltk
from nltk.tag.stanford import StanfordNERTagger

text = u"""
Some economists have responded positively to Bitcoin, including
Francois R. Velde, senior economist of the Federal Reserve in Chicago
who described it as "an elegant solution to the problem of creating a
digital currency." In November 2013 Richard Branson announced that
Virgin Galactic would accept Bitcoin as payment, saying that he had invested
in Bitcoin and found it "fascinating how a whole new global currency
has been created", encouraging others to also invest in Bitcoin.
Other economists commenting on Bitcoin have been critical.
Economist Paul Krugman has suggested that the structure of the currency
incentivizes hoarding and that its value derives from the expectation that
others will accept it as payment. Economist Larry Summers has expressed
a "wait and see" attitude when it comes to Bitcoin. Nick Colas, a market
strategist for ConvergEx Group, has remarked on the effect of increasing
use of Bitcoin and its restricted supply, noting, "When incremental
adoption meets relatively fixed supply, it should be no surprise that
prices go up. And that’s exactly what is happening to BTC prices.
"""

st = StanfordNERTagger('stanford-ner/english.all.3class.distsim.crf.ser.gz',
                       'stanford-ner/stanford-ner.jar')

for sent in nltk.sent_tokenize(text):
    tokens = nltk.tokenize.Word_tokenize(sent)
    tags = st.tag(tokens)
    for tag in tags:
        if tag[1] in ["PERSON", "LOCATION", "ORGANIZATION"]:
            print(tag)

Ergebnisse

(u'Bitcoin', u'LOCATION')       # wrong
(u'Francois', u'PERSON')
(u'R.', u'PERSON')
(u'Velde', u'PERSON')
(u'Federal', u'ORGANIZATION')
(u'Reserve', u'ORGANIZATION')
(u'Chicago', u'LOCATION')
(u'Richard', u'PERSON')
(u'Branson', u'PERSON')
(u'Virgin', u'PERSON')         # Wrong
(u'Galactic', u'PERSON')       # Wrong
(u'Bitcoin', u'PERSON')        # Wrong
(u'Bitcoin', u'LOCATION')      # Wrong
(u'Bitcoin', u'LOCATION')      # Wrong
(u'Paul', u'PERSON')
(u'Krugman', u'PERSON')
(u'Larry', u'PERSON')
(u'Summers', u'PERSON')
(u'Bitcoin', u'PERSON')        # Wrong
(u'Nick', u'PERSON')
(u'Colas', u'PERSON')
(u'ConvergEx', u'ORGANIZATION')
(u'Group', u'ORGANIZATION')     
(u'Bitcoin', u'LOCATION')       # Wrong
(u'BTC', u'ORGANIZATION')       # Wrong
1
Martin Thoma

Ich möchte hier eine brutale und gierige Lösung posten, um das Problem von @Enthusiast zu lösen: wenn möglich den vollständigen Namen einer Person erhalten.

Die Großschreibung des ersten Zeichens in jedem Namen wird als Kriterium für die Erkennung von PERSON in Spacy verwendet. Beispielsweise wird "Jim Hoffman" selbst nicht als benannte Entität erkannt, während "Jim Hoffman" dies sein wird.

Wenn unsere Aufgabe einfach darin besteht, Personen aus einem Skript auszuwählen, können wir einfach zuerst den ersten Buchstaben jedes Wortes in Großbuchstaben schreiben und ihn dann in spacy ablegen.

import spacy

def capitalizeWords(text):

  newText = ''

  for sentence in text.split('.'):
    newSentence = ''
    for Word in sentence.split():
      newSentence += Word+' '
    newText += newSentence+'\n'

  return newText

nlp = spacy.load('en_core_web_md')

doc = nlp(capitalizeWords(rawText))

#......

Beachten Sie, dass dieser Ansatz vollständige Namen auf Kosten der Erhöhung von Fehlalarmen abdeckt.

0
Maxmoe

Das hat für mich ziemlich gut funktioniert. Ich musste nur eine Zeile ändern, damit sie ausgeführt werden konnte. 

    for subtree in sentt.subtrees(filter=lambda t: t.node == 'PERSON'):

muss sein

    for subtree in sentt.subtrees(filter=lambda t: t.label() == 'PERSON'):

Es gab Unvollkommenheiten in der Ausgabe (beispielsweise wurde "Geldwäsche" als Person identifiziert), bei meinen Daten ist eine Namensdatenbank jedoch möglicherweise nicht zuverlässig. 

0
C.Rider