Kapitel 4 Morphologische Analyse, Kapitel 5 Abhängigkeitsanalyse und Sprachverarbeitung 100 Ich habe dieses Problem mit Python3 gelöst. Derzeit benötige ich nicht die Inhalte von "Kapitel 6: Verarbeiten von englischem Text" und "Kapitel 7: Datenbank", daher überspringe ich sie und fahre mit "Kapitel 8: Maschinelles Lernen" fort. ..
Was meinen Wissensstand angeht, ich habe Python noch nie bei der Arbeit verwendet. Ich habe eine Einführungsstunde bei Coursera genommen. Ich bin ein absoluter Amateur in der Verarbeitung natürlicher Sprache / maschinelles Lernen, aber ich plane, es von nun an bei der Arbeit zu verwenden. Es ist ein Gefühl.
In diesem Kapitel kann ich nicht mehr verstehen, was in der Problemstellung steht, daher werde ich die Erklärung der Begriffe aufschreiben.
--Erstellen Sie aus jedem Überprüfungssatz ein Modell, das vorhersagt, ob jede Bewertung positiv oder negativ ist.
In diesem Kapitel [Satzpolaritätsdatensatz] von Movie Review Data, veröffentlicht von Bo Pang und Lillian Lee. v1.0](http://www.cs.cornell.edu/people/pabo/movie-review-data/rt-polaritydata.README.1.0.txt) wird verwendet, um den Satz positiv oder negativ zu machen. Arbeiten Sie an der Aufgabe (Polaritätsanalyse), um sie als (negativ) zu klassifizieren.
Erstellen Sie die richtigen Antwortdaten (sentiment.txt) wie folgt mit den richtigen Antwortdaten der Polaritätsanalyse für Sätze.
Fügen Sie die Zeichenfolge "+1" am Anfang jeder Zeile in rt-polarity.pos ein (Polaritätsbezeichnung "+1" gefolgt von einem Leerzeichen gefolgt von positivem Anweisungsinhalt). Fügen Sie die Zeichenfolge "-1" am Anfang jeder Zeile in rt-polarity.neg ein (Polaritätsbezeichnung "-1" gefolgt von einem Leerzeichen gefolgt von einer negativen Anweisung). Verketten Sie den Inhalt von 1 und 2 oben und sortieren Sie die Zeilen nach dem Zufallsprinzip Überprüfen Sie nach dem Erstellen von sentiment.txt die Anzahl der positiven Beispiele (positive Sätze) und die Anzahl der negativen Beispiele (negative Sätze).
--_ Polarität __: Wenn ein sprachlicher Ausdruck wie ein Satz, eine Phrase oder ein Wort eine positive oder negative Bedeutung hat, wird "positiv" oder "negativ" als Polarität des sprachlichen Ausdrucks bezeichnet. Die automatische Bestimmung der Polarität ist eine grundlegende Technik für die Verarbeitung von Reputationsinformationen.
ml/Main.py
from ml.Sentiment import Sentiments, Util
from ml.Model import LogisticRegression
import matplotlib.pyplot as plt
sentiments = Sentiments()
sentiments.restore_from_pos_neg_file('../8_ML/rt-polarity.pos', '../8_ML/rt-polarity.neg')
sentiments.shuffle()
sentiments.save('../8_ML/70_sentiment.txt')
ml/Sentiments.py
import random
import re
from itertools import chain
from nltk.stem.porter import PorterStemmer
from stop_words import get_stop_words
from ml.Model import LogisticRegression
class Sentiments:
"""
Klasse, die die Liste der Bewertungen verwaltet
"""
def __init__(self) -> None:
self.all = []
def restore_from_pos_neg_file(self, pos_file: str, neg_file: str) -> None:
"""
Behalten Sie positive und negative Sätze als Liste mit polaren Bezeichnungen.
Als polare Bezeichnung für positive Sätze'1'Als polare Bezeichnung für negative Sätze'-1'Anziehen.
:param pos_Datei Datei, die positiven Text speichert(latin_1)
:param neg_Datei Eine Datei, in der negative Sätze gespeichert sind(latin_1)
"""
with open(pos_file, encoding='latin_1') as input_file:
self.all += [{'label': 1, 'sentence': line.replace('\n', '')} for line in input_file]
with open(neg_file, encoding='latin_1') as input_file:
self.all += [{'label': -1, 'sentence': line.replace('\n', '')} for line in input_file]
def shuffle(self):
random.shuffle(self.all)
--71. Erstellen Sie eine entsprechende Liste der englischen Stoppwörter (Stoppliste). Implementieren Sie außerdem eine Funktion, die true zurückgibt, wenn das als Argument angegebene Wort (Zeichenfolge) in der Stoppliste enthalten ist, andernfalls false. Schreiben Sie außerdem einen Test für diese Funktion.
--72. Entwerfen Sie Ihre eigenen Merkmale, die für die Polaritätsanalyse nützlich sein können, und extrahieren Sie die Merkmale aus den Trainingsdaten. Was die Natur betrifft, wäre die Mindestgrundlinie diejenige, bei der die Stoppwörter aus der Überprüfung entfernt wurden und jedes Wort stammte.
--__ Stoppwörter __: Eine Liste von Wörtern, die beim Abrufen von Informationen aus Indexwörtern entfernt werden sollen. Es besteht aus Wörtern, die für das Abrufen von Informationen nicht als wirksam angesehen werden, z. B. Zusatzwörter und Wörter mit allgemeinen Bedeutungen wie sein und haben. Da die Anzahl der Stoppwörter begrenzt ist, werden sie häufig im Voraus manuell erstellt. Ich bin ein wenig verwirrt über "mach es richtig", aber als ich einen kurzen Blick darauf warf, wie es anderen Leuten geht, "mach es wirklich texto", "mach es durch morphologische Analyse + Frequenzanalyse", "allgemein im Netz" Es scheint, dass einige Leute Methoden anwenden wie "eine Liste aufheben und sie solide schreiben". Ich werde hier ein Python-Paket namens Stoppwörter verwenden.
--__ Merkmal : Bezieht sich auf Informationen, die als Hinweis zur Klassifizierung von Daten während des maschinellen Lernens verwendet werden können. Wird auch als Funktion für maschinelles Lernen bezeichnet. Wenn Sie beispielsweise ein Modell zum Schätzen des Teils eines Wortes maschinell lernen, werden die Wörter und Teile, die vor und nach dem Wort erscheinen, als Lernelemente verwendet. Mit anderen Worten, lernen Sie ein Modell, das den Teil des Zielworts anhand der Wörter und Teile, die davor und danach erscheinen, als Hinweise schätzt. Was als Lernfähigkeit verwendet wird, ist ein wichtiger Faktor, der den Erfolg oder Misserfolg der Verarbeitung natürlicher Sprache basierend auf maschinellem Lernen bestimmt. -- Lerndaten _: Daten, die zum automatischen Trainieren eines Klassifizierungsmodells im maschinellen Lernen verwendet werden. Trainingsdaten. Es sind die Überprüfungsdaten (Stimmungsliste), die in sentiment.txt gespeichert sind. -- Stemming-Prozess (Stemming) : Stiel = Stiel. Der Wortstamm wird auch als Wortbasis bezeichnet und ist der Teil, der sich nicht ändert, wenn sich die Wortform ändert. Zum Beispiel ist im Fall des Verbs "werfen" "werfen" der Stamm. Stemming ist die Umwandlung des Wortes "werfen" in "werfen". In Python kann es mit der Stammmethode der PorterStemmer-Klasse im Paket nltk.stem.porter ausgeführt werden. (Es ist in "52. Stemming" aufgenommen.) -- Gestalte deine Identität __: Entwerfen Sie Ihre eigenen Funktionen, die für die Polaritätsanalyse hilfreich sein können. .. .. Was soll ich machen? Zusätzlich zum Stoppwortentfernungs- und Stemming-Prozess, der die Mindestgrundlinie in der Problemstellung darstellt, ist die Anzahl der Vorkommen zu hoch (10.000-mal oder mehr) oder zu gering (3-mal oder weniger), und es scheint, dass die Polarität nicht beeinflusst wird. Ich habe versucht, das Wort aus dem Hintergrund zu entfernen, aber am Ende habe ich keine guten Ergebnisse erzielt, daher werde ich hier mit der minimalen Grundlinie fortfahren.
Wir werden eine Identitätsliste für jede Bewertung hinzufügen, die Gefühle haben.
ml/Main.py
sentiments.add_features()
sentiments.save('../8_ML/72_sentiment.txt')
ml/Sentiments.py
class Sentiments:
#Eingeführte Methode
def __init__(self) -> None: ...
def restore_from_pos_neg_file(self, pos_file: str, neg_file: str) -> None: ...
#Unten 1.Identitätsdesign(71.Stoppwort/ 72.Identitätsextraktion)Methode zum Hinzufügen mit
def add_features(self):
stemmer = PorterStemmer()
#Wir werden den Trainingsdaten Identitätsinformationen hinzufügen
for sentiment in self.all:
words = re.compile(r'[,.:;\s]').split(sentiment['sentence'])
features = []
for word in words:
stem = stemmer.stem(word)
# if not (stop_words.is_stop_word(stem) or is_freq_word(stem) or stem == ''):
if not (Util.is_stop_word(stem) or stem == ''):
features.append(stem)
sentiment['features'] = list(set(features))
class Util:
stop_words = get_stop_words('english')
@staticmethod
def is_stop_word(_word: str) -> bool:
"""
Gibt true zurück, wenn das im Argument angegebene Wort (Zeichenfolge) in der Stoppliste enthalten ist, andernfalls false.
:param _Wort Wort
:True, wenn das im Argument return bool angegebene Wort (Zeichenfolge) in der Stoppliste enthalten ist, andernfalls false
"""
return _word in Util.stop_words
- Lernen Sie das logistische Regressionsmodell anhand der in 73 extrahierten Eigenschaften. 72. --Überprüfen Sie die 10 wichtigsten Merkmale mit hohem Gewicht und die 10 wichtigsten Merkmale mit niedrigem Gewicht im logistischen Regressionsmodell, das in 75,73 gelernt wurde.
--__ Lernen Sie das logistische Regressionsmodell __ Ich verstehe nicht genug, um die genaue Definition zu erklären, aber er sagte: "Berechnen Sie aus der Korrespondenz zwischen" Etikett "und" Merkmalen ", die in 72 erstellt wurde, den" Gewichtsvektor "unter Verwendung der Identifikationsfunktion (Sigmoidfunktion)." Ich werde es vorläufig verstehen.
--__ Gewichtsvektor __ Eine Sammlung von Werten, die angeben, wie stark sich jede Eigenschaft auf das Ergebnis auswirkt (in Python als Diktattyp ausgedrückt). Wenn Sie beispielsweise das folgende Programm ausführen, sehen Sie diktierte Gewichte wie {..., 'perfekt': 1.829376624682014, 'Bemerkung': 1.8879018752394459, 'langweilig': -2.8891666516371806, 'Bohrung': -3.153237996082115, ... Ich kann es bekommen. Dies ist wahrscheinlich eine positive Bewertung, wenn das Wort "perfekt" oder "Bemerkung" (Stamm) im Bewertungstext enthalten ist, und es ist wahrscheinlich eine negative Bewertung, wenn das Wort "langweilig" oder "langweilig" enthalten ist. Es kann als solches interpretiert werden. Es ist eine Zahl, die intuitiv vernünftig erscheint.
--____ Identifikationsfunktion (Sigmoidfunktion) __ Eine Funktion, die die Möglichkeit einer positiven Überprüfung unter Verwendung eines Gewichtsvektors und einer Identitätsliste als Eingaben vorhersagt. Intern interessiert uns die Berechnungslogik hier nicht.
--__ Lernrate __ Passen Sie an, wie viel sich der Parameter mit einer einzelnen Aktualisierung mit einem geeigneten positiven Wert bewegt. Je höher die Lernrate, desto schneller das Lernen, aber die Vorhersagewahrscheinlichkeit ist nicht stabil. Es scheint üblich zu sein, den Anfangswert auf etwa 0,1 einzustellen und ihn mit fortschreitendem Lernen allmählich zu verringern, aber hier wird er nach Versuch und Irrtum auf 0,6 eingestellt.
ml/Main.py
model = LogisticRegression()
model.calc_weights(sentiments=sentiments.all)
ml/Model.py
import math
from collections import defaultdict
class LogisticRegression:
def __init__(self):
self.weights = defaultdict(float) #Gewichtsvektor
def predict(self, _features: list) -> float:
"""
Diskriminierungsfunktion:Prognostizieren Sie die Möglichkeit einer positiven Überprüfung anhand des Gewichtsvektors und der Identitätsliste als Eingaben
:param _Features Eine Liste von Hintergründen, die nach Überprüfungstext geordnet sind
:return Wahrscheinlichkeit einer positiven Bewertung
"""
#Inneres Produkt aus Gewichtsvektor und Identitätsliste
x = sum([self.weights[feature] for feature in _features])
#Sigmaid-Funktion
return 1.0 / (1.0 + math.exp(-x))
def update(self, _features: list, _label: int, _eta: float) -> None:
"""
Aktualisieren Sie den Gewichtsvektor.
:param _Features Eine Liste von Hintergründen, die nach Überprüfungstext geordnet sind
:param _Etikett Etikett, das dem Überprüfungstext beigefügt ist(Positive Bewertung:+1 /Negative Bewertung:-1)
:param _eta Lernrate
"""
#Antwort durch die Diskriminanzfunktion vorhergesagt(Wahrscheinlichkeit einer positiven Bewertung)
predict_answer = self.predict(_features)
#Ob es sich tatsächlich um eine positive Bewertung handelt(Konvertieren Sie Beschriftungen in Wahrscheinlichkeiten(-1 => 0.0000, 1 => 1.0000))
actual_answer = (float(_label) + 1) / 2
#Gewichtsvektor aktualisieren
for _feature in _features:
_dif = _eta * (predict_answer - actual_answer)
#Aktualisieren Sie nicht, wenn der Unterschied zu nahe an 0 kommt
if 0.0002 > abs(self.weights[_feature] - _dif):
continue
self.weights[_feature] -= _dif
def calc_weights(self, eta0: float = 0.6, etan: float = 0.9999, sentiments: list = None) -> None:
"""
Gewichtsvektor berechnen
:param eta0 Anfangslernrate
:param etan Lernratenreduktionsrate
:param sentiments Liste der Wörterbücher mit Überprüfungsbezeichnungen, Sätzen und Identitätsliste
"""
for idx, sentiment in enumerate(sentiments):
self.update(sentiment['features'], sentiment['label'], eta0 * (etan ** idx))
def save_weights(self, file_name: str) -> None:
"""
Schreiben Sie den Gewichtsvektor in eine Datei(Sortieren)
:param file_Name Dateiname
"""
with open(file_name, mode='w', encoding='utf-8') as output:
for k, v in sorted(self.weights.items(), key=lambda x: x[1]):
output.write('{}\t{}\n'.format(k, v))
def restore_weights(self, file_name: str) -> dict:
"""
Stellen Sie den Gewichtsvektor aus der Datei wieder her
:param file_name Dateiname, in dem der Gewichtsvektor gespeichert ist
:Rückgabegewichtsvektor
"""
weights = {}
with open(file_name, encoding='utf-8') as input_file:
for line in input_file:
key, value = line.split()
weights[key] = float(value)
self.weights = weights
--Verwenden Sie das in 73 erlernte logistische Regressionsmodell. Implementieren Sie ein Programm, das die Polaritätsbezeichnung eines bestimmten Satzes ("+1" für ein positives Beispiel, "-1" für ein negatives Beispiel) und seine Vorhersagewahrscheinlichkeit berechnet. .. --76. Wenden Sie das logistische Regressionsmodell auf die Trainingsdaten an und geben Sie das richtige Etikett, das vorhergesagte Etikett und die vorhergesagte Wahrscheinlichkeit in tabulatorgetrenntem Format aus. --77. Erstellen Sie ein Programm, das die Ausgabe von 76 empfängt und die richtige Antwortrate der Vorhersage, die richtige Antwortrate für das richtige Beispiel, die Rückrufrate und die F1-Punktzahl erhält.
ml/Mian.py
sentiments.add_predict(model.predict)
score = sentiments.calc_score()
Util.print_score(score, '77.Messung der richtigen Antwortrate')
ml/Sentiments.py
class Sentiments:
#Eingeführte Methode
def __init__(self) -> None: ...
def restore_from_pos_neg_file(self, pos_file: str, neg_file: str) -> None: ...
def add_features(self) -> None: ...
#Unten die Methode, die hier hinzugefügt werden soll
def add_predict(self, predict_func: classmethod, threshold: float = 0.0):
for sentiment in self.all:
probability = predict_func(sentiment['features'])
sentiment['probability'] = probability
if probability > 0.5 + threshold:
sentiment['predict_label'] = 1
elif probability < 0.5 - threshold:
sentiment['predict_label'] = -1
else:
sentiment['predict_label'] = 0
def calc_score(self) -> dict:
count = 0
correct_count = 0
actual_positive_count = 0
predict_positive_count = 0
correct_positive_count = 0
for sentiment in self.all:
count += 1
correct = int(sentiment['label']) == int(sentiment['predict_label'])
positive = int(sentiment['label']) == 1
predict_positive = int(sentiment['predict_label']) == 1
if correct:
correct_count += 1
if positive:
actual_positive_count += 1
if predict_positive:
predict_positive_count += 1
if correct and predict_positive:
correct_positive_count += 1
precision_rate = correct_positive_count / predict_positive_count
recall_rate = correct_positive_count / actual_positive_count
f_value = (2 * precision_rate * recall_rate) / (precision_rate + recall_rate)
return {
'correct_rate': correct_count / count,
'precision_rate': precision_rate,
'recall_rate': recall_rate,
'f_value': f_value
}
class Util:
#Eingeführte Methode
def is_stop_word(_word: str) -> bool: ...
#Unten die Methode, die hier hinzugefügt werden soll
@staticmethod
def print_score(score: dict, title: str = '') -> None:
print('\n{}\n\t Vorhersagegenauigkeitsrate: {}\n\t Konformitätsrate für positive Beispiele: {}\n\Ich erinnere mich nicht: {}\n\tF1 Punktzahl: {}'.format(
title, score['correct_rate'], score['precision_rate'], score['recall_rate'], score['f_value']))
Es scheint, dass es nicht stark entfernt werden sollte.
77.Messung der richtigen Antwortrate
Vorhersagegenauigkeitsrate: 0.8743200150065654
Compliance-Rate für positive Fälle: 0.8564029290944811
Erinnern: 0.8994560120052523
F1-Punktzahl: 0.8774016468435498
Im Experiment 76-77 wurde der für das Lernen verwendete Fall auch für die Bewertung verwendet, sodass nicht gesagt werden kann, dass es sich um eine gültige Bewertung handelt. Das heißt, der Klassifizierer bewertet die Leistung beim Speichern des Trainingsfalls und misst nicht die Generalisierungsleistung des Modells. Finden Sie daher die richtige Antwortrate, Präzisionsrate, Rückrufrate und F1-Bewertung der Polaritätsklassifizierung durch den 5-Divisions-Kreuztest.
--__ 5 Split Cross Test __: Eine Methode zum Teilen der Trainingsdaten in 5 Teile, wobei 4 für das Training und 1 zum Testen verwendet werden, um das Modell 5 Mal mit verschiedenen Kombinationen zu erstellen und zu bewerten.
ml/Main.py
sentiments.restore('../8_ML/72_sentiment.txt') #Stellen Sie verlernte Gefühle wieder her.
score = sentiments.cross_validation(model=LogisticRegression())
Util.print_score(score, '78.5-Split-Kreuztest')
ml/Sentiments.py
class Sentiments:
#Eingeführte Methode
def __init__(self) -> None: ...
def restore_from_pos_neg_file(self, pos_file: str, neg_file: str) -> None: ...
def add_features(self) -> None: ...
def add_predict(self, predict_func: classmethod, threshold: float = 0.0) -> None: ...
def calc_score(self) -> dict: ...
#Unten die Methode, die hier hinzugefügt werden soll
def restore(self, file: str):
_sentiments = []
with open(file, encoding='utf-8') as input_file:
for line in input_file:
_label, _sentence, _features_str, _probability, _predict_label = line.split('\t')
_sentiments.append({
'label': int(_label),
'sentence': _sentence,
'features': _features_str.split(' '),
'probability': 0 if _probability == '' else float(_probability),
'predict_label': 0 if _predict_label.rstrip() == '' else float(_predict_label)
})
self.all = _sentiments
def cross_validation(self, _divide_count: int = 5, model: LogisticRegression = None, threshold: float = 0.0) -> dict:
divided_list = Util.divide_list(self.all, _divide_count)
_scores = []
for i in range(_divide_count):
#Lernen
learning_data = list(chain.from_iterable([divided_list[x] for x in [_i for _i in range(_divide_count) if _i != i]]))
model.calc_weights(sentiments=learning_data)
#Prüfung
self.all = divided_list[i]
self.add_predict(model.predict, threshold)
_scores.append(self.calc_score())
return {
'correct_rate': sum([_score['correct_rate'] for _score in _scores]) / _divide_count,
'precision_rate': sum([_score['precision_rate'] for _score in _scores]) / _divide_count,
'recall_rate': sum([_score['recall_rate'] for _score in _scores]) / _divide_count,
'f_value': sum([_score['f_value'] for _score in _scores]) / _divide_count
}
class Util:
#Eingeführte Methode
def is_stop_word(_word: str) -> bool: ...
def print_score(score: dict, title: str = '') -> None: ...
#Unten die Methode, die hier hinzugefügt werden soll
@staticmethod
def divide_list(lst: list, count: int) -> list:
"""
Teilen Sie die Liste durch die angegebene Nummer
:Parameter Liste, die geteilt werden soll
:param count Wie viele müssen geteilt werden?
:Rückgabeliste Geteilte Liste
"""
divided_list = []
list_len = len(lst) / count
for _i in range(count):
begin_index = int(_i * list_len)
end_index = int((_i + 1) * list_len if _i + 1 < count else len(lst))
divided_list.append(lst[begin_index:end_index])
return divided_list
Natürlich ist es niedriger als 77, aber es ist keine so große Verschlechterung.
78.5-Split-Kreuztest
Vorhersagegenauigkeitsrate: 0.848988423671968
Compliance-Rate für positive Fälle: 0.8481575029900081
Erinnern: 0.852642297684391
F1-Punktzahl: 0.8503632552717463
Zeichnen Sie ein Präzisionsrückrufdiagramm, indem Sie den Klassifizierungsschwellenwert des logistischen Regressionsmodells ändern.
--Threshold: Bisher haben wir festgestellt, dass das vorhergesagte Label positiv ist, wenn die Wahrscheinlichkeit 0,5 oder mehr beträgt, und ansonsten negativ. Es scheint, dass dieses Kriterium als Schwelle bezeichnet wird.
Lassen Sie uns den Schwellenwert in Schritten von 0,05 von 0,0 auf 0,45 ändern und den Übergang von Präzisionsrate und Rückrufrate beobachten.
ml/Main.py
precision_rates = []
recall_rates = []
thresholds = [t / 20 for t in range(10)]
for threshold in thresholds:
sentiments.restore('../8_ML/72_sentiment.txt') #Stellen Sie verlernte Gefühle wieder her.
score = sentiments.cross_validation(model=LogisticRegression(), threshold=threshold)
precision_rates.append(score['precision_rate'])
recall_rates.append(score['recall_rate'])
print(thresholds)
print(precision_rates)
print(recall_rates)
plt.plot(thresholds, precision_rates, label="precision", color="red")
plt.plot(thresholds, recall_rates, label="recall", color="blue")
plt.xlabel("threshold")
plt.ylabel("rate")
plt.xlim(-0.05, 0.5)
plt.ylim(0, 1)
plt.title("Logistic Regression")
plt.legend(loc=3)
plt.show()
Das Erhöhen des Schwellenwerts bedeutet, nur dann vorherzusagen, wenn dies absolut sicher ist. Je höher der Schwellenwert, desto höher die Präzisionsrate. Im Gegenteil, die Rückrufquote wird sinken, da sie nur vorhergesagt wird, wenn sie absolut sicher ist.
Recommended Posts