In diesem Artikel werde ich Scikit-Learn mit Knock 100 Language Processing Kapitel 6 erklären.
Lassen Sie uns zuerst "pip install scikit-learn" ausführen.
Laden Sie den News Aggregator-Datensatz herunter und erstellen Sie die folgenden Trainingsdaten (train.txt), Verifizierungsdaten (valid.txt) und Bewertungsdaten (test.txt).
Entpacken Sie die heruntergeladene Zip-Datei und lesen Sie die Erklärung zu readme.txt. Es werden nur Fälle (Artikel) extrahiert, in denen die Informationsquelle (Herausgeber) "Reuters", "Huffington Post", "Businessweek", "Contactmusic.com" und "Daily Mail" ist. Sortieren Sie die extrahierten Fälle nach dem Zufallsprinzip. Teilen Sie 80% der extrahierten Fälle in Trainingsdaten und die restlichen 10% in Verifizierungsdaten und Bewertungsdaten auf und speichern Sie sie unter den Dateinamen train.txt, valid.txt bzw. test.txt. Schreiben Sie einen Fall pro Zeile in die Datei und verwenden Sie das durch Tabulatoren getrennte Format des Kategorienamens und der Artikelüberschrift (diese Datei wird später in Frage 70 wiederverwendet).
Überprüfen Sie nach dem Erstellen der Trainingsdaten und Bewertungsdaten die Anzahl der Fälle in jeder Kategorie.
Dieses Problem hat nichts mit Scicit-Learn zu tun, sodass Sie es nach Ihren Wünschen lösen können. Laden Sie zunächst die Datei herunter und lesen Sie readme.txt.
!wget https://archive.ics.uci.edu/ml/machine-learning-databases/00359/NewsAggregatorDataset.zip
!unzip -c NewsAggregatorDataset.zip readme.txt
Readme ist in Ordnung, aber ich möchte komprimierte Dateien verarbeiten, ohne sie so weit wie möglich zu dekomprimieren. Die Zip-Datei des Datenkörpers sollte vom zipfile-Modul verarbeitet werden. Zum Lesen kann jede Methode verwendet werden. In diesem Fall ist Pandas verwenden einfach. Lassen Sie sklearn.model_selection.train_test_split () die Aufteilung durchführen. Es mischt auch.
Als rudimentäre Geschichte lautet der Bibliotheksname scikit-learn, aber der Modulname beim Importieren lautet sklearn.
import csv
import zipfile
import pandas as pd
from sklearn.model_selection import train_test_split
with zipfile.ZipFile("NewsAggregatorDataset.zip") as z:
with z.open("newsCorpora.csv") as f:
names = ('ID','TITLE','URL','PUBLISHER','CATEGORY','STORY','HOSTNAME','TIMESTAMP')
df = pd.read_table(f, names=names, quoting=csv.QUOTE_NONE)
publisher_set = {"Reuters", "Huffington Post", "Businessweek", "Contactmusic.com", "Daily Mail"}
df = df[df['PUBLISHER'].isin(publisher_set)]
df, valid_test_df = train_test_split(df, train_size=0.8, random_state=0)
df.to_csv('train.txt', columns=('CATEGORY','TITLE'), sep='\t', header=False, index=False)
valid_df, test_df = train_test_split(valid_test_df, test_size=0.5, random_state=0)
valid_df.to_csv('valid.txt', columns=('CATEGORY','TITLE'), sep='\t', header=False, index=False)
test_df.to_csv('test.txt', columns=('CATEGORY','TITLE'), sep='\t', header=False, index=False)
pandas.read_table () liest eine TSV-Datei und erstellt ein Objekt vom Typ DataFrame. names legt den Spaltennamen fest. quoting = csv.QUOTE_NONE
ist eine Einstellung, mit der das Anführungszeichen als Zeichenfolge behandelt wird. csv.QUOTE_NONE
ist das gleiche, auch wenn Sie 3
schreiben.
(Ich habe gehört, dass "read_table ()" früher veraltet war, sodass Sie "read_csv (sep =" \ t ")" verwenden können, aber es scheint, dass es nicht mehr unterstützt wird, weil es keine Warnung gibt.)
Der Teil df ['PUBLISHER']
ist eine Operation zum Extrahieren von Spalten, und der Rückgabewert ist vom Typ Series
. Der Pandas-Typ "DataFrame" stellte die Struktur der gesamten Tabelle dar, und jede Spalte wurde durch den Typ "Series" dargestellt. Seine Methode "isin ()" gibt die "Reihe" des Wahrheitswertes der "in" -Operation für jedes Element zurück. Und wenn Sie es so übergeben, als wäre es ein df-Schlüssel, wird ein "DataFrame" zurückgegeben, der nur die True-Zeilen extrahiert.
names = ('CATEGORY','TITLE')
df = pd.read_table('train.txt', names=names, quoting=csv.QUOTE_NONE)
df['CATEGORY'].value_counts()
b 4503
e 4254
t 1210
m 717
Name: CATEGORY, dtype: int64
df = pd.read_table('test.txt', names=names, quoting=csv.QUOTE_NONE)
df['CATEGORY'].value_counts()
b 565
e 518
t 163
m 90
Name: CATEGORY, dtype: int64
Extrahieren Sie die Funktionen aus den Trainingsdaten, Verifizierungsdaten und Bewertungsdaten und speichern Sie sie unter den Dateinamen "train.feature.txt", "valid.feature.txt" und "test.feature.txt". Entwerfen Sie die Funktionen, die für die Kategorisierung wahrscheinlich nützlich sind. Die minimale Grundlinie wäre eine Artikelüberschrift, die in eine Wortfolge konvertiert wird.
In diesem Problem wird nicht gesagt, dass die extrahierten Merkmale in einen Vektor (eine Matrix) konvertiert werden sollten. Es scheint erforderlich zu sein, den Funktionsumfang in einem für Menschen lesbaren Format zu speichern, um ihn später für die Fehleranalyse zu verwenden.
(Wenn Sie "Count vectorizer" von "scikit-learn" verwenden, wird die Merkmalsextraktion und -vektorisierung als Satz durchgeführt, der mit diesem Problem nicht vertraut ist.)
Extrahieren Sie daher die Funktionen selbst, erstellen Sie ein Wörterbuchobjekt, speichern Sie es und verwenden Sie im nächsten Problem Dictvectorizer. Wir werden es mit der Politik der Vektorisierung mit lösen. Der Schlüssel des Wörterbuchs ist der Name der Feature-Menge und der Wert ist 1.0. Es ist eine binäre Natur. Erstellen eines Wörterbuchs aus Feature-Mengen Dieser Vorgang ist auch für die Inferenz erforderlich. Machen Sie ihn daher zu einer Funktion.
Das Speicherformat der Feature-Menge ist nicht angegeben, aber ich denke, das JSONL-Format ist unter dem Gesichtspunkt der Lesbarkeit besser.
Ich möchte Kommas und Anführungszeichen von Wörtern trennen. Es ist egal, wie du es machst. SpaCy ist als Tokenizer bekannt, aber ich denke, dass der Tokenizer von "Count vectorizer" auch bei diesem Problem wirksam ist.
q51.py
import argparse
import json
from sklearn.feature_extraction.text import CountVectorizer
def ngram_gen(seq, n):
return zip(*(seq[i:] for i in range(n)))
nlp = CountVectorizer().build_tokenizer()
def make_feats_dict(title):
words = nlp(title)
feats = {}
for token in words:
feats[token] = 1.0
for bigram in ngram_gen(words, 2):
feats[' '.join(bigram)] = 1.0
for trigram in ngram_gen(words, 3):
feats[' '.join(trigram)] = 1.0
return feats
def dump_features(input_file, output_file):
with open(input_file) as fi, open(output_file, 'w') as fo:
for line in fi:
vals = line.rstrip().split('\t')
label, title = vals
feats = {'**LABEL**': label}
feats.update(make_feats_dict(title))
print(json.dumps(feats), file=fo)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('input_file')
parser.add_argument('output_file')
args = vars(parser.parse_args())
dump_features(**args)
if __name__ == '__main__':
main()
Overwriting q51.py
!python q51.py test.txt test.feature.txt
!python q51.py valid.txt valid.feature.txt
!python q51.py train.txt train.feature.txt
ngram_gen ()
macht ngram. Transponieren Sie für Bigram "[[Ich bin ein NLPer], [bin ein NLPer]" (gemäß dem kürzeren)! Ich mache es auf elegante Weise.
(Das Etikett ist keine Merkmalsmenge, aber ich schreibe es aus, weil es das nächste Problem lindert.)
Ich mache etwas Seltsames mit der Hauptfunktion, aber dies wird auch in Kapitel 4 Auspacken der Argumentliste verwendet. Ich versuche, Schlüsselwortargumente in einem Wörterbuch über Argumentlisten zu übergeben. Da der Rückgabewert von "parse_args ()" ein Namespace-Objekt ist, wird er von "vars ()" (wie in Kapitel 5 beschrieben) in ein Wörterbuchobjekt konvertiert.
Lernen Sie das logistische Regressionsmodell anhand der in> 51 erstellten Trainingsdaten.
Erstellen Sie zunächst eine Liste "X", die aus einem Wörterbuch besteht, das die Feature-Menge aus der in 51 erstellten Datei darstellt. Um es in das Modell des maschinellen Lernens einzugeben, benötigen wir einen Vektor, der die Werte aller Merkmale auflistet. Verwenden Sie daher DictVectorizer (). Die fit (X)
-Methode des DictVectorizer
ruft die Feature-Name-Index-Zuordnung vom X
ab und speichert sie in einer Variablen innerhalb der Instanz. Verwenden Sie dann "transform (X)", um "X" in eine "numpy" -Matrix umzuwandeln. Fit_transform (X)
macht das alles auf einmal.
Verwenden Sie dann LogisticRegression (). Instanziieren Sie einfach und rufen Sie die Methode "fit (X, y)" auf, um den Gewichtsvektor in der Instanz zu lernen. Hypara ist auf Instanziierung eingestellt. X
ist wie eine Matrix, y
ist wie eine Liste und es ist in Ordnung, wenn sie die gleiche Länge haben.
Speichern Sie das trainierte Modell unter Modellpersistenz. Bei Verwendung von joblib.dump () wird eine große Anzahl von Dateien generiert, sofern nicht das optionale Argument "compress" angegeben wird. Also sei vorsichtig.
Wenn Sie zu diesem Zeitpunkt die Zuordnung zwischen dem Namen der Feature-Menge und dem Index nicht speichern, treten beim Ableiten Probleme auf. Lassen Sie uns jede Instanz von DictVectorizer
sichern.
q52.py
import argparse
import json
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.linear_model import LogisticRegression
import joblib
def argparse_imf():
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input')
parser.add_argument('-m', '--model')
parser.add_argument('-f', '--feats')
args = parser.parse_args()
return args
def load_xy(filename):
X = []
y = []
with open(filename) as f:
for line in f:
dic = json.loads(line)
y.append(dic.pop('**LABEL**'))
X.append(dic)
return X, y
def main():
args = argparse_imf()
X_train, y_train = load_xy(args.input)
vectorizer = DictVectorizer()
X_train = vectorizer.fit_transform(X_train)
y_train = np.array(y_train)
clf = LogisticRegression(random_state=0, max_iter=1000, verbose=1)
clf.fit(X_train, y_train)
joblib.dump(clf, args.model, compress=3)
joblib.dump(vectorizer, args.feats, compress=3)
if __name__ == '__main__':
main()
Overwriting q52.py
!python q52.py -i train.feature.txt -m train.logistic.model -f train.feature.joblib
Verwenden Sie das in> 52 erlernte logistische Regressionsmodell und implementieren Sie ein Programm, das die Kategorie und ihre Vorhersagewahrscheinlichkeit aus der angegebenen Artikelüberschrift berechnet.
Ich bin der Meinung, dass sich die "angegebene Artikelüberschrift" in dieser Frage nicht auf die oben erstellten Testdaten bezieht, sondern vielmehr auf Vorhersagen aus einer Artikelüberschrift.
Wenn Sie das gespeicherte Modell laden und "Vorhersagen (X)" aufrufen, wird die Beschriftung ausgegeben, und wenn Sie "Vorhersagen_Proba (X)" aufrufen, wird die Vorhersagewahrscheinlichkeit ausgegeben. Dieses X
kann erhalten werden, indem aus der Eingabe ein Feature-Wörterbuch erstellt und mit dem in 52 gespeicherten Dictvectorizer ()
konvertiert wird.
Wenn Sie zwei Titel eingeben und pred_proba ()
anwenden, erhalten Sie eine solche numpy.ndarray
.
>>> y_proba
array([[0.24339871, 0.54111814, 0.10059608, 0.11488707],
[0.19745579, 0.69644375, 0.04204659, 0.06405386]])
Vorhersagewahrscheinlichkeiten für alle Labels werden veröffentlicht, aber ich denke, Sie möchten nur den Maximalwert. was soll ich machen? Es scheint, dass "ndarray" eine [max () -Methode] hat (https://numpy.org/doc/stable/reference/generated/numpy.ndarray.max.html) ...
>>> y_proba.max()
0.6964437549683299
>>> y_proba.max(axis=0)
array([0.24339871, 0.69644375, 0.10059608, 0.11488707])
Geben wir unser Bestes. Unten finden Sie ein Beispiel für die Antwort.
q53.py
import argparse
import json
import sys
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.linear_model import LogisticRegression
import joblib
from q51 import make_feats_dict
from q52 import argparse_imf, load_xy
def predict_label_proba(X, vectorizer, clf):
X = vectorizer.transform(X)
y_proba = clf.predict_proba(X)
y_pred = clf.classes_[y_proba.argmax(axis=1)]
y_proba_max = y_proba.max(axis=1)
return y_pred, y_proba_max
def main():
args = argparse_imf()
vectorizer = joblib.load(args.feats)
clf = joblib.load(args.model)
X = list(map(make_feats_dict, sys.stdin))
y_pred, y_proba = predict_label_proba(X, vectorizer, clf)
for label, proba in zip(y_pred, y_proba):
print('%s\t%.4f' % (label, proba))
if __name__ == '__main__':
main()
Overwriting q53.py
!echo 'I have a dog.' | python q53.py -m train.logistic.model -f train.feature.joblib
e 0.5441
Messen Sie die korrekte Antwortrate des in> 52 erlernten logistischen Regressionsmodells anhand der Trainingsdaten und Bewertungsdaten.
Sie können es von Hand implementieren, aber ich überlasse es sklearn.metrics.accuracy_score ().
Das Wichtigste beim Lernen von "Scikit-Learn" ist der bisherige Ablauf.
Dictvectorizer.fit_transform ()
in eine Matrixfit (X_train, y_train)
Lassen Sie uns das festhalten.
q54.py
import argparse
import json
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import joblib
from q52 import argparse_imf, load_xy
def predict(args):
X_test, y_true = load_xy(args.input)
vectorizer = joblib.load(args.feats)
X_test = vectorizer.transform(X_test)
y_true = np.array(y_true)
clf = joblib.load(args.model)
y_pred = clf.predict(X_test)
return y_true, y_pred
def main():
args = argparse_imf()
y_true, y_pred = predict(args)
accuracy = accuracy_score(y_true, y_pred) * 100
print('Accuracy: %.3f' % accuracy)
if __name__ == '__main__':
main()
Overwriting q54.py
!python q54.py -i train.feature.txt -m train.logistic.model -f train.feature.joblib
Accuracy: 99.897
!python q54.py -i test.feature.txt -m train.logistic.model -f train.feature.joblib
Accuracy: 87.275
Erstellen Sie eine Verwirrungsmatrix des in> 52 erlernten logistischen Regressionsmodells für die Trainingsdaten und Bewertungsdaten.
Überlassen Sie es sklearn.metrics.confusion_matrix ().
q55.py
from sklearn.metrics import confusion_matrix
from q52 import argparse_imf
from q54 import predict
def main():
args = argparse_imf()
y_true, y_pred = predict(args)
labels = ('b', 'e', 't', 'm')
matrix = confusion_matrix(y_true, y_pred, labels=labels)
print(labels)
print(matrix)
if __name__ == '__main__':
main()
Overwriting q55.py
!python q55.py -i train.feature.txt -m train.logistic.model -f train.feature.joblib
('b', 'e', 't', 'm')
[[4499 1 3 0]
[ 2 4252 0 0]
[ 3 1 1206 0]
[ 0 1 0 716]]
!python q55.py -i test.feature.txt -m train.logistic.model -f train.feature.joblib
('b', 'e', 't', 'm')
[[529 26 10 0]
[ 13 503 2 0]
[ 37 36 89 1]
[ 19 26 0 45]]
Messen Sie die Genauigkeit, den Rückruf und die F1-Bewertung des logistischen Regressionsmodells, das in> 52 anhand der Bewertungsdaten gelernt wurde. Ermitteln Sie die Genauigkeitsrate, die Rückrufrate und die F1-Bewertung für jede Kategorie und integrieren Sie die Leistung für jede Kategorie in den Mikro- und Makro-Durchschnitt.
Überlassen Sie es sklearn.metrics.classification_report (). Bei der Klassifizierung mit mehreren Klassen (Einzeletikett) entspricht der Mikrodurchschnitt für alle Klassen der korrekten Antwortrate (Referenz).
q56.py
from sklearn.metrics import classification_report
from q52 import argparse_imf
from q54 import predict
def main():
args = argparse_imf()
y_true, y_pred = predict(args)
print(classification_report(y_true, y_pred, digits=4))
if __name__ == '__main__':
main()
Overwriting q56.py
!python q56.py -i test.feature.txt -m train.logistic.model -f train.feature.joblib
precision recall f1-score support
b 0.8846 0.9363 0.9097 565
e 0.8511 0.9710 0.9071 518
m 0.9783 0.5000 0.6618 90
t 0.8812 0.5460 0.6742 163
accuracy 0.8728 1336
macro avg 0.8988 0.7383 0.7882 1336
weighted avg 0.8775 0.8728 0.8633 1336
Überprüfen Sie die Top-10-Features mit hohen Gewichten und die Top-10-Features mit niedrigen Gewichten im logistischen Regressionsmodell, das in> 52 gelernt wurde.
Das Attribut "coef_" hat eine Gewichtung, aber da es sich um eine Klassifizierung mit mehreren Klassen handelt, ist die Gewichtung die Anzahl der Klassen x die Anzahl der Feature-Labels. Werden alle 4 Klassen ausgegeben?
q57.py
import joblib
import numpy as np
from q52 import argparse_imf
def get_topk_indices(array, k=10):
unsorted_max_indices = np.argpartition(-array, k)[:k]
max_weights = array[unsorted_max_indices]
max_indices = np.argsort(-max_weights)
return unsorted_max_indices[max_indices]
def show_weights(args):
vectorizer = joblib.load(args.feats)
feature_nemes = np.array(vectorizer.get_feature_names())
clf = joblib.load(args.model)
coefs = clf.coef_
y_labels = clf.classes_
for coef, y_label in zip(coefs, y_labels):
max_k_indices = get_topk_indices(coef)
print(y_label)
for name, weight in zip(feature_nemes[max_k_indices], coef[max_k_indices]):
print(name, weight, sep='\t')
print('...')
min_k_indices = get_topk_indices(-coef)
for name, weight in zip(feature_nemes[min_k_indices], coef[min_k_indices]):
print(name, weight, sep='\t')
print()
def main():
args = argparse_imf()
show_weights(args)
if __name__ == '__main__':
main()
Overwriting q57.py
!python q57.py -i test.feature.txt -m train.logistic.model -f train.feature.joblib
Es ist ein Umweg wie dieser, weil ich nur die oberen und unteren Ebenen möchte, anstatt das gesamte "coef_" zu "sortieren". Dies liegt daran, dass es in numpy keine topk ()
-ähnliche Funktion gibt und es keine andere Wahl gibt, als den oberen Index zu erhalten, der nicht nach argpartition ()
sortiert ist.
Beim Training eines logistischen Regressionsmodells kann der Grad der Überanpassung während des Trainings durch Anpassen der Regularisierungsparameter gesteuert werden. Lernen Sie das logistische Regressionsmodell mit verschiedenen Regularisierungsparametern und finden Sie die richtige Antwortrate für die Trainingsdaten, Validierungsdaten und Bewertungsdaten. Fassen Sie die Ergebnisse des Experiments in einem Diagramm mit den Regularisierungsparametern auf der horizontalen Achse und der Genauigkeitsrate auf der vertikalen Achse zusammen.
import argparse
import json
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import joblib
import matplotlib.pyplot as plt
from tqdm import tqdm
from q52 import load_xy
def get_accuracy(clf, X, y_true):
y_pred = clf.predict(X)
return accuracy_score(y_true, y_pred)
X_train, y_train = load_xy('train.feature.txt')
X_valid, y_valid = load_xy('valid.feature.txt')
X_test, y_test = load_xy('test.feature.txt')
vectorizer = DictVectorizer()
X_train = vectorizer.fit_transform(X_train)
X_valid = vectorizer.transform(X_valid)
X_test = vectorizer.transform(X_test)
train_accuracies = []
valid_accuracies = []
test_accuracies = []
for exp in tqdm(range(10)):
clf = LogisticRegression(random_state=0, max_iter=1000, C=2**exp)
clf.fit(X_train, y_train)
train_accuracies.append(get_accuracy(clf, X_train, y_train))
valid_accuracies.append(get_accuracy(clf, X_valid, y_valid))
test_accuracies.append(get_accuracy(clf, X_test, y_test))
cs = [2**c for c in range(10)]
plt.plot(cs, train_accuracies, label='train')
plt.plot(cs, valid_accuracies, label='valid')
plt.plot(cs, test_accuracies, label='test')
plt.legend()
plt.show()
Lernen Sie das Kategorisierungsmodell, während Sie den Lernalgorithmus und die Lernparameter ändern. Suchen Sie den Lernalgorithmusparameter, der die höchste Genauigkeitsrate für die Verifizierungsdaten ergibt. Finden Sie auch die richtige Antwortrate in den Bewertungsdaten, wenn der Lernalgorithmus und die Parameter verwendet werden.
Die High-Para-Auswahl des Algorithmus sollte anhand der Verifizierungsdaten und nicht anhand der Testsatzabstimmung erfolgen. Aber diesmal habe ich nicht so viel getan und am Ende sklearn.ensemble.GradientBoostingClassifier
verwendet ... Ich wollte es beenden.
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier(random_state=0, min_samples_split=0.01,
min_samples_leaf=5, max_depth=10,
max_features='sqrt', n_estimators=500,
subsample=0.8)
clf.fit(X_train, y_train)
valid_acc = get_accuracy(clf, X_valid, y_valid) * 100
print('Validation Accuracy: %.3f' % valid_acc)
test_acc = get_accuracy(clf, X_test, y_test) * 100
print('Test Accuracy: %.3f' % test_acc)
Validation Accuracy: 88.997
Test Accuracy: 88.548
Es ist ein trendiger GBDT! Ich habe es versucht, aber es war schwierig, weil sich die Leistung mit hohem Para erheblich geändert hat. Wenn ich Zeit habe, würde ich ernsthaft eine Rastersuche durchführen ...
Wenn es um maschinelles Lernen in Python geht, denke ich, dass es ein Kapitel ist, in dem Sie Scikit-Learn lernen können.
Recommended Posts