** Extraktion eindeutiger Ausdrücke ** ist eine Technologie, die die richtige Nomenklatur wie ** Personenname ** und ** Ortsname **, die im Text erscheinen, sowie numerische Ausdrücke wie ** Datum ** und ** Uhrzeit ** extrahiert. .. Die Extraktion eindeutiger Ausdrücke wird auch als Elementartechnologie für angewandte Anwendungen verwendet, die die Verarbeitung natürlicher Sprache verwenden, z. B. ** Frage- und Antwortsystem **, ** Dialogsystem ** und ** Informationsextraktion **.
Dieses Mal werde ich einen einzigartigen Ausdrucksextraktor mit ** Technologie für maschinelles Lernen ** erstellen.
※Vorsichtsmaßnahmen Es kommt keine theoretische Geschichte heraus. Wenn Sie die Theorie wissen wollen, schlagen Sie bitte die andere. </ font>
Dieser Abschnitt bietet einen Überblick und eine Methode zur Extraktion eindeutiger Ausdrücke.
Die Extraktion eindeutiger Ausdrücke ist eine Technologie, die die richtige Nomenklatur wie Personennamen und Ortsnamen, die in Texten vorkommen, sowie numerische Ausdrücke wie Datum und Uhrzeit extrahiert. Schauen wir uns ein konkretes Beispiel an. Extrahieren wir den richtigen Ausdruck aus dem folgenden Satz.
Taro besuchte Hanako am 18. Mai um 9 Uhr morgens.
Wenn die im obigen Satz enthaltenen eindeutigen Ausdrücke extrahiert werden, ** Taro ** und ** Hanako ** als ** Personenname **, ** 18. Mai ** als ** Datum **, ** Zeit ** als ** 9 Uhr ** kann extrahiert werden.
Im obigen Beispiel wurden der Name, das Datum und die Uhrzeit der Person als Klassen eindeutiger Ausdrücke extrahiert. Im Allgemeinen die folgenden acht Klassen (Übung zum Abrufen und Extrahieren von Informationen (IREX) Aufgabe zum Extrahieren spezifischer Ausdrücke Definition) in: //nlp.cs.nyu.edu/irex/NE/) wird häufig verwendet.
Klasse | Beispiel |
---|---|
ART einzigartiger Produktname | Nobelpreis für Literatur, Windows 7 |
LOC Ortsname | Präfektur Chiba, USA |
ORG Organisation | LDP, NHK |
PSN Personenname | Shinzo Abe, Mercel |
DAT Datum | 29. Januar 2016/01/29 |
TIM Zeit | 15 Uhr, 10 Uhr:30 |
MNY Betrag | 241 Yen, 8 Dollar |
PNT-Verhältnis | 10%, 30% |
Eine Möglichkeit, Eigenausdrücke zu extrahieren, besteht darin, Sätze zu kennzeichnen, die morphologisch analysiert wurden. Das Folgende ist ein Beispiel für die morphologische Analyse des Satzes "Taro ist am 18. Mai um 9 Uhr morgens ..." und die anschließende Kennzeichnung.
Die Bezeichnungen B-XXX und I-XXX geben an, dass diese Zeichenfolgen eindeutige Ausdrücke sind. B-XXX bedeutet den Beginn der eindeutigen Ausdruckszeichenfolge, und I-XXX bedeutet, dass die richtige Ausdruckszeichenfolge fortgesetzt wird. Der XXX-Teil enthält eine eindeutige Ausdrucksklasse wie ORG oder PSN. Der nicht geschützte Teil ist mit O gekennzeichnet.
Das Beschriften kann mithilfe von Regeln erfolgen, diesmal jedoch mithilfe der ** Technologie für maschinelles Lernen **. Das heißt, es erstellt ein Modell aus vorbeschrifteten Trainingsdaten und verwendet dieses Modell, um unbeschriftete Anweisungen zu kennzeichnen. Insbesondere lernen wir die Verwendung eines Algorithmus namens CRF.
Bewegen wir tatsächlich unsere Hände.
Beginnen Sie mit der Installation der erforderlichen Python-Module. Führen Sie den folgenden Befehl im Terminal aus, um das Modul zu installieren. Ich habe CRFsuite als CRF-Bibliothek installiert.
pip install numpy
pip install scipy
pip install sklearn
pip install python-crfsuite
Importieren Sie nach der Installation die erforderlichen Module. Führen Sie den folgenden Code aus.
from itertools import chain
import pycrfsuite
import sklearn
from sklearn.metrics import classification_report
from sklearn.preprocessing import LabelBinarizer
Da CRF das Lernen überwacht, benötigen wir Daten, die mit Lehrerdaten gekennzeichnet sind. Dieses Mal habe ich die markierten Daten im Voraus vorbereitet. Bitte herunterladen von hier. Der Dateiname lautet "hironsan.txt".
Definieren wir nun zunächst eine Klasse zum Lesen der heruntergeladenen Daten.
import codecs
class CorpusReader(object):
def __init__(self, path):
with codecs.open(path, encoding='utf-8') as f:
sent = []
sents = []
for line in f:
if line == '\n':
sents.append(sent)
sent = []
continue
morph_info = line.strip().split('\t')
sent.append(morph_info)
train_num = int(len(sents) * 0.9)
self.__train_sents = sents[:train_num]
self.__test_sents = sents[train_num:]
def iob_sents(self, name):
if name == 'train':
return self.__train_sents
elif name == 'test':
return self.__test_sents
else:
return None
Laden Sie als Nächstes die heruntergeladenen Daten mit der erstellten Klasse. Die Anzahl der Trainingsdaten beträgt 450 Sätze und die Anzahl der Testdaten beträgt 50 Sätze.
c = CorpusReader('hironsan.txt')
train_sents = c.iob_sents('train')
test_sents = c.iob_sents('test')
Das Format der gelesenen Daten ist wie folgt. Das IOB2-Tag wird nach Durchführung der morphologischen Analyse mit dem morphologischen Analysegerät "MeCab" angebracht. Die Daten sind in Sätze unterteilt, und jeder Satz besteht aus einer Sammlung mehrerer morphologischer Informationen.
>>> train_sents[0]
[['2005', 'Substantiv', 'Nummer', '*', '*', '*', '*', '*', 'B-DAT'],
['Jahr', 'Substantiv', 'Suffix', 'Hilfswörter', '*', '*', '*', 'Jahr', 'Nen', 'Nen', 'I-DAT'],
['7', 'Substantiv', 'Nummer', '*', '*', '*', '*', '*', 'I-DAT'],
['Mond', 'Substantiv', 'Allgemeines', '*', '*', '*', '*', 'Mond', 'Mond', 'Mond', 'I-DAT'],
['14', 'Substantiv', 'Nummer', '*', '*', '*', '*', '*', 'I-DAT'],
['Tag', 'Substantiv', 'Suffix', 'Hilfswörter', '*', '*', '*', 'Tag', 'Nichi', 'Nichi', 'I-DAT'],
['、', 'Symbol', 'Lesepunkt', '*', '*', '*', '*', '、', '、', '、', 'O'],
...
]
Als Nächstes werde ich die Funktionen erläutern, die zum Extrahieren eindeutiger Ausdrücke verwendet werden.
Wir geben Ihnen einen Überblick darüber, was Sie verwenden werden, und codieren es dann.
Als nächstes werde ich die zu verwendende Natur erklären. Dieses Mal werden wir Wörter mit zwei Buchstaben vor und nach der Unterklassifizierung von Teiltexten, Zeichentyp und eindeutigem Ausdruckstag verwenden. Ein Beispiel für die Verwendung dieser Eigenschaften ist unten dargestellt. Der vom Rahmen umgebene Teil ist die verwendete Natur.
Die Klassifizierung der Zeichentypen ist wie folgt. Insgesamt gibt es 7 Typen.
Zeichentyp-Tag | Erläuterung |
---|---|
ZSPACE | Leer |
ZDIGIT | Arabische Zahlen |
ZLLET | Niedrigere alphabetische Zeichen |
ZULET | Alphabet Hauptstadt |
HIRAG | Hiragana |
KATAK | Katakana |
OTHER | Andere |
Der als Identität verwendete Zeichentyp ist eine Kombination aller im Wort enthaltenen Zeichentypen. Zum Beispiel umfasst das Wort "viele" Kanji und Hiragana. Das Zeichentyp-Tag für Hiragana ist HIRAG und das Zeichentyp-Tag für Kanji ist OTHER. Daher ist der Zeichentyp des Wortes "viele" "HIRAG-OTHER".
Der Code zum Bestimmen des Zeichentyps lautet wie folgt. Alle in der Zeichenfolge enthaltenen Zeichentypen werden mit- (Bindestrich) kombiniert.
def is_hiragana(ch):
return 0x3040 <= ord(ch) <= 0x309F
def is_katakana(ch):
return 0x30A0 <= ord(ch) <= 0x30FF
def get_character_type(ch):
if ch.isspace():
return 'ZSPACE'
elif ch.isdigit():
return 'ZDIGIT'
elif ch.islower():
return 'ZLLET'
elif ch.isupper():
return 'ZULET'
elif is_hiragana(ch):
return 'HIRAG'
elif is_katakana(ch):
return 'KATAK'
else:
return 'OTHER'
def get_character_types(string):
character_types = map(get_character_type, string)
character_types_str = '-'.join(sorted(set(character_types)))
return character_types_str
Der Code zum Extrahieren der Teilwort-Unterklasse aus den morphologischen Informationen lautet wie folgt.
def extract_pos_with_subtype(morph):
idx = morph.index('*')
return '-'.join(morph[1:idx])
Basierend auf dem Obigen ist der Code zum Extrahieren der Identität für jedes Wort wie folgt. Es ist ein bisschen überflüssig, aber Sie können es sehen.
def word2features(sent, i):
word = sent[i][0]
chtype = get_character_types(sent[i][0])
postag = extract_pos_with_subtype(sent[i])
features = [
'bias',
'word=' + word,
'type=' + chtype,
'postag=' + postag,
]
if i >= 2:
word2 = sent[i-2][0]
chtype2 = get_character_types(sent[i-2][0])
postag2 = extract_pos_with_subtype(sent[i-2])
iobtag2 = sent[i-2][-1]
features.extend([
'-2:word=' + word2,
'-2:type=' + chtype2,
'-2:postag=' + postag2,
'-2:iobtag=' + iobtag2,
])
else:
features.append('BOS')
if i >= 1:
word1 = sent[i-1][0]
chtype1 = get_character_types(sent[i-1][0])
postag1 = extract_pos_with_subtype(sent[i-1])
iobtag1 = sent[i-1][-1]
features.extend([
'-1:word=' + word1,
'-1:type=' + chtype1,
'-1:postag=' + postag1,
'-1:iobtag=' + iobtag1,
])
else:
features.append('BOS')
if i < len(sent)-1:
word1 = sent[i+1][0]
chtype1 = get_character_types(sent[i+1][0])
postag1 = extract_pos_with_subtype(sent[i+1])
features.extend([
'+1:word=' + word1,
'+1:type=' + chtype1,
'+1:postag=' + postag1,
])
else:
features.append('EOS')
if i < len(sent)-2:
word2 = sent[i+2][0]
chtype2 = get_character_types(sent[i+2][0])
postag2 = extract_pos_with_subtype(sent[i+2])
features.extend([
'+2:word=' + word2,
'+2:type=' + chtype2,
'+2:postag=' + postag2,
])
else:
features.append('EOS')
return features
def sent2features(sent):
return [word2features(sent, i) for i in range(len(sent))]
def sent2labels(sent):
return [morph[-1] for morph in sent]
def sent2tokens(sent):
return [morph[0] for morph in sent]
Extrahieren Sie die Identität mit sent2features aus dem Satz. Die Eigenschaften, die tatsächlich extrahiert werden, sind wie folgt.
>>> sent2features(train_sents[0])[0]
['bias',
'word=2005',
'type=ZDIGIT',
'postag=Substantiv-Nummer',
'BOS',
'BOS',
'+1:word=Jahr',
'+1:type=OTHER',
'+1:postag=Substantiv-Suffix-Hilfswörter',
'+2:word=7',
'+2:type=ZDIGIT',
'+2:postag=Substantiv-Nummer']
Es stellt sich heraus, dass die Identität aus den Daten extrahiert werden kann. Extrahieren Sie die Qualitäten und Etiketten für Trainings- und Testdaten aus den Daten für die spätere Verwendung.
X_train = [sent2features(s) for s in train_sents]
y_train = [sent2labels(s) for s in train_sents]
X_test = [sent2features(s) for s in test_sents]
y_test = [sent2labels(s) for s in test_sents]
Um das Modell zu trainieren, erstellen Sie ein pycrfsuite.Trainer-Objekt, laden Sie die Trainingsdaten und rufen Sie dann die Zugmethode auf. Erstellen Sie zunächst ein Trainer-Objekt und laden Sie die Trainingsdaten.
trainer = pycrfsuite.Trainer(verbose=False)
for xseq, yseq in zip(X_train, y_train):
trainer.append(xseq, yseq)
Als nächstes stellen Sie die Lernparameter ein. Ursprünglich sollte anhand von Entwicklungsdaten entschieden werden, diesmal wird dies jedoch behoben.
trainer.set_params({
'c1': 1.0, # coefficient for L1 penalty
'c2': 1e-3, # coefficient for L2 penalty
'max_iterations': 50, # stop earlier
# include transitions that are possible, but not observed
'feature.possible_transitions': True
})
Jetzt, da wir fertig sind, trainieren wir das Modell. Geben Sie den Dateinamen an und führen Sie die Zugmethode aus.
trainer.train('model.crfsuite')
Nach Abschluss der Ausführung wird eine Datei mit dem angegebenen Dateinamen erstellt. Darin ist das trainierte Modell gespeichert.
Um das trainierte Modell zu verwenden, erstellen Sie ein pycrfsuite.Tagger-Objekt, laden Sie das trainierte Modell und verwenden Sie die Tag-Methode. Erstellen Sie zunächst ein Tagger-Objekt und laden Sie das trainierte Modell.
tagger = pycrfsuite.Tagger()
tagger.open('model.crfsuite')
Lassen Sie uns nun den Satz markieren.
example_sent = test_sents[0]
print(' '.join(sent2tokens(example_sent)))
print("Predicted:", ' '.join(tagger.tag(sent2features(example_sent))))
print("Correct: ", ' '.join(sent2labels(example_sent)))
Sie sollten folgendes Ergebnis erhalten: Vorausgesagt ist die mit dem erstellten Modell vorhergesagte Tag-Zeichenfolge, und Richtig ist die richtige Tag-Zeichenfolge. Im Fall dieses Satzes stimmten das erwartete Ergebnis des Modells und die richtigen Antwortdaten überein.
Im Oktober letzten Jahres wurden 34 Menschen bei einer Explosion in Taba, Ägypten, in der Nähe des Ortes getötet.
Predicted: B-DAT I-DAT I-DAT O O O O O O O O O O O O B-LOC O B-LOC O O O O O O O O O O
Correct: B-DAT I-DAT I-DAT O O O O O O O O O O O O B-LOC O B-LOC O O O O O O O O O O
Damit ist der Aufbau des Eigenexpressionsextraktors abgeschlossen.
Ich habe ein Modell erstellt, weiß aber nicht, ob dies gut oder schlecht ist. Daher ist es wichtig, das erstellte Modell zu bewerten. Lassen Sie uns nun das erstellte Modell bewerten. Die Bewertung basiert auf der Genauigkeitsrate, der Rückrufrate und dem F-Wert. Unten finden Sie den zu bewertenden Code.
def bio_classification_report(y_true, y_pred):
lb = LabelBinarizer()
y_true_combined = lb.fit_transform(list(chain.from_iterable(y_true)))
y_pred_combined = lb.transform(list(chain.from_iterable(y_pred)))
tagset = set(lb.classes_) - {'O'}
tagset = sorted(tagset, key=lambda tag: tag.split('-', 1)[::-1])
class_indices = {cls: idx for idx, cls in enumerate(lb.classes_)}
return classification_report(
y_true_combined,
y_pred_combined,
labels = [class_indices[cls] for cls in tagset],
target_names = tagset,
)
Tag-Anweisungen im Testdatensatz zur Verwendung bei der Auswertung.
y_pred = [tagger.tag(xseq) for xseq in X_test]
Die mit dem trainierten Modell markierten Daten und die richtigen Antwortdaten werden an die Bewertungsfunktion übergeben und das Ergebnis angezeigt. Für jede Kategorie werden die Genauigkeitsrate, die Rückrufrate, der F-Wert und die Anzahl der Tags angezeigt.
>>> print(bio_classification_report(y_test, y_pred))
precision recall f1-score support
B-ART 1.00 0.89 0.94 9
I-ART 0.92 1.00 0.96 12
B-DAT 1.00 1.00 1.00 12
I-DAT 1.00 1.00 1.00 22
B-LOC 1.00 0.95 0.97 55
I-LOC 0.94 0.94 0.94 17
B-ORG 0.75 0.86 0.80 14
I-ORG 1.00 0.90 0.95 10
B-PSN 0.00 0.00 0.00 3
B-TIM 1.00 0.71 0.83 7
I-TIM 1.00 0.81 0.90 16
avg / total 0.95 0.91 0.93 177
Ich denke, das Ergebnis ist etwas zu gut, aber die verwendeten Daten enthielten wahrscheinlich ähnliche Aussagen.
※Hinweis Möglicherweise erhalten Sie eine UndefinedMetricWarning. Es scheint nicht möglich zu sein, die Genauigkeitsrate usw. für Etiketten zu definieren, die in der vorhergesagten Stichprobe nicht vorhanden sind. Weil die Anzahl der vorbereiteten Daten gering ist ...
Dieses Mal konnte ich mithilfe von crfsuite, einer Python-Bibliothek, auf einfache Weise einen eindeutigen Ausdrucksextraktor erstellen. Basierend auf der Definition von IREX werden dem Tagging acht eindeutige Ausdrücke hinzugefügt. Die Definition von IREX ist jedoch für den praktischen Gebrauch oft grob. Daher ist es bei Verwendung der Eigenausdrucksextraktion für eine Aufgabe erforderlich, Daten mit den erforderlichen Tags entsprechend der Aufgabe vorzubereiten.
Ich denke auch, dass es eine gute Idee ist, nach besseren Eigenschaften und Modellparametern zu suchen.