Dies ist die Aufzeichnung des 73. "Lernens" von Language Processing 100 Knock 2015. Es hat viel Zeit gekostet, Nachforschungen anzustellen und Versuch und Irrtum zu machen.
Bis jetzt habe ich es nicht in den Block gepostet, da es im Grunde dasselbe war wie "Amateur-Sprachverarbeitung 100 Klopfen". , "Kapitel 8: Maschinelles Lernen" wurde ernst genommen und teilweise geändert. Ich werde posten. Ich benutze hauptsächlich scikit-learn.
Verknüpfung | Bemerkungen |
---|---|
073_1.Lernen(Vorverarbeitung).ipynb | Antwortprogramm(Vorverarbeitung編)GitHub-Link |
073_2.Lernen(Ausbildung).ipynb | Antwortprogramm(Ausbildung編)GitHub-Link |
100 Klicks Amateur-Sprachverarbeitung:73 | Ich bin Ihnen immer mit 100 Sprachverarbeitungsklopfen zu Dank verpflichtet |
Einführung in Python mit 100 Klopfen Sprachverarbeitung#73 -Maschinelles Lernen, Scikit-Logistische Rückkehr mit Lernen | scikit-Klopfen Sie das Ergebnis mit lernen |
Art | Ausführung | Inhalt |
---|---|---|
OS | Ubuntu18.04.01 LTS | Es läuft virtuell |
pyenv | 1.2.15 | Ich benutze pyenv, weil ich manchmal mehrere Python-Umgebungen benutze |
Python | 3.6.9 | python3 auf pyenv.6.Ich benutze 9 3.7 oder 3.Es gibt keinen tiefen Grund, keine 8er-Serie zu verwenden Pakete werden mit venv verwaltet |
In der obigen Umgebung verwende ich die folgenden zusätzlichen Python-Pakete. Einfach mit normalem Pip installieren.
Art | Ausführung |
---|---|
nltk | 3.4.5 |
stanfordnlp | 0.2.0 |
pandas | 0.25.3 |
scikit-learn | 0.21.3 |
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.
Lernen Sie das logistische Regressionsmodell anhand der in> 72 extrahierten Eigenschaften.
Ich habe Stanford NLP zum Entfernen von Stoppwörtern und zur Verarbeitung von Lemma-Stemming verwendet. Es hat lange gedauert, daher habe ich es in Vorverarbeitung und Lernen unterteilt.
Ich verwende tf-idf, um Wörter zu vektorisieren. tf-idf berechnet die Wichtigkeit basierend auf zwei Indikatoren, tf (Termfrequenz) und idf (Inverse Dokumentfrequenz). Verringern Sie die Wichtigkeit von Wörtern (allgemeinen Wörtern), die in vielen Dokumenten vorkommen, und erhöhen Sie die Wichtigkeit von Wörtern, die nur in bestimmten Dokumenten vorkommen.
Um ehrlich zu sein, konnte ich nicht beurteilen, ob tf-idf auch bei der Stoppwortverarbeitung gültig war, also [CountVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer. Wir vektorisieren und vergleichen die Genauigkeit mit der einfachen Worthäufigkeit unter Verwendung von HTML. Wir vergleichen auch die Hyperparameter der logistischen Regression mit einer Rastersuche.
Erstens ist die Vorverarbeitung. Was wir jedoch tun, ist [Vorheriges "Antwortprogramm (Analyse) 072_2. Identitätsextraktion (Analyse) .ipynb"](https://qiita.com/FukuharaYohei/items/f1a12d8e63fc576a456f#%E5%9B % 9E% E7% AD% 94% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% A0% E5% 88% 86% E6% 9E% 90 % E7% B7% A8-072_2% E7% B4% A0% E6% 80% A7% E6% 8A% BD% E5% 87% BA% E5% 88% 86% E6% 9E% 90ipynb Es gibt nichts Besonderes zu erwähnen. Der Nachteil ist, dass die Verarbeitung etwa eine Stunde dauert.
import warnings
import re
import csv
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer as PS
import stanfordnlp
#Definiert als Taple für Geschwindigkeit
STOP_WORDS = set(stopwords.words('english'))
# Stemmer
ps = PS()
#Scheint mit Universal POS-Tags kompatibel zu sein
# https://universaldependencies.org/u/pos/
EXC_POS = {'PUNCT', #Interpunktion
'X', #Andere
'SYM', #Symbol
'PART', #Partikel('s etc.)
'CCONJ', #Verbindung(und soweiter und sofort.)
'AUX', #Hilfsverb(würde etc.)
'PRON', #Gleichbedeutend
'SCONJ', #Untergeordneter Konnektiv(ob etc.)
'ADP', #Konjunkt(in etc.)
'NUM'} #Nummer
#Es war langsam, alle Standardprozessoren anzugeben, also beschränken Sie sich auf das Minimum
# https://stanfordnlp.github.io/stanfordnlp/processors.html
nlp = stanfordnlp.Pipeline(processors='tokenize,pos,lemma')
reg_sym = re.compile(r'^[!-/:-@[-`{-~]|[!-/:-@[-`{-~]$')
reg_dit = re.compile('[0-9]')
#Entfernen von führenden und nachfolgenden Symbolen
def remove_symbols(lemma):
return reg_sym.sub('', lemma)
#Beenden Sie die Beurteilung der Wortauthentizität
def is_stopword(word):
lemma = remove_symbols(word.lemma)
return True if lemma in STOP_WORDS \
or lemma == '' \
or word.upos in EXC_POS \
or len(lemma) == 1 \
or reg_dit.search(lemma)\
else False
#Warnung ausblenden
warnings.simplefilter('ignore', UserWarning)
with open('./sentiment.txt') as file_in:
with open('./sentiment_stem.txt', 'w') as file_out:
writer = csv.writer(file_out, delimiter='\t')
writer.writerow(['Lable', 'Lemmas'])
for i, line in enumerate(file_in):
print("\r{0}".format(i), end="")
lemma = []
#Die ersten 3 Zeichen geben nur negativ / positiv an. Führen Sie daher keine nlp-Verarbeitung durch(Mach es so schnell wie möglich)
doc = nlp(line[3:])
for sentence in doc.sentences:
lemma.extend([ps.stem(remove_symbols(word.lemma)) for word in sentence.words if is_stopword(word) is False])
writer.writerow([1 if line[0] == '+' else 0, ' '.join(lemma)])
Dies ist der Trainingsteil des Hauptfachs.
import csv
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.base import BaseEstimator, TransformerMixin
#Klasse zur Verwendung der Wortvektorisierung in GridSearchCV
class myVectorizer(BaseEstimator, TransformerMixin):
def __init__(self, method='tfidf', min_df=0.0005, max_df=0.10):
self.method = method
self.min_df = min_df
self.max_df = max_df
def fit(self, x, y=None):
if self.method == 'tfidf':
self.vectorizer = TfidfVectorizer(min_df=self.min_df, max_df=self.max_df)
else:
self.vectorizer = CountVectorizer(min_df=self.min_df, max_df=self.max_df)
self.vectorizer.fit(x)
return self
def transform(self, x, y=None):
return self.vectorizer.transform(x)
#Parameter für GridSearchCV
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0004, 0.0005],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #Ich habe auch 10 ausprobiert, aber der SCORE ist niedrig, nur weil er langsam ist
'classifier__solver': ['newton-cg', 'liblinear']},
]
#Datei lesen
def read_csv_column(col):
with open('./sentiment_stem.txt') as file:
reader = csv.reader(file, delimiter='\t')
header = next(reader)
return [row[col] for row in reader]
x_all = read_csv_column(1)
y_all = read_csv_column(0)
def train(x_train, y_train, file):
pipline = Pipeline([('vectorizer', myVectorizer()), ('classifier', LogisticRegression())])
#clf steht für Klassifizierung
clf = GridSearchCV(
pipline, #
PARAMETERS, #Parametersatz, den Sie optimieren möchten
cv = 5) #Anzahl der Kreuztests
clf.fit(x_train, y_train)
pd.DataFrame.from_dict(clf.cv_results_).to_csv(file)
print('Grid Search Best parameters:', clf.best_params_)
print('Grid Search Best validation score:', clf.best_score_)
print('Grid Search Best training score:', clf.best_estimator_.score(x_train, y_train))
train(x_all, y_all, 'gs_result.csv')
TfidfVectorizer oder CountVectorizer /sklearn.feature_extraction.text.CountVectorizer.html) wird für die Wortvektorisierung verwendet.
Es ist etwas verwirrend, da es so klassifiziert ist, dass es mit der Funktion GridSearchCV
verwendet werden kann, aber die wichtigen Punkte sind wie folgt.
def fit(self, x, y=None):
if self.method == 'tfidf':
self.vectorizer = TfidfVectorizer(min_df=self.min_df, max_df=self.max_df)
else:
self.vectorizer = CountVectorizer(min_df=self.min_df, max_df=self.max_df)
self.vectorizer.fit(x)
return self
def transform(self, x, y=None):
return self.vectorizer.transform(x)
Verwenden Sie "fit", um aus allen Wörtern zu lernen, und "transformieren", um die Wortfolge zu transformieren. Die Parameter sind TfidfVectorizer und CountVectorizer. /generated/sklearn.feature_extraction.text.CountVectorizer.html) Beide verwenden die folgenden beiden.
--min_df: Wenn die Häufigkeit des Auftretens unter dem angegebenen Verhältnis liegt, wird es von der Vektorisierung ausgeschlossen. Es wird angegeben, weil davon ausgegangen wird, dass "Lernen nicht möglich ist, wenn die Häufigkeit des Auftretens zu gering ist". --max_df: Wird von der Vektorisierung ausgeschlossen, wenn sie häufiger als der angegebene Prozentsatz auftritt. Dieses Mal dachte ich, dass "Wörter wie" Film "bedeutungslos sind" und spezifizierte es.
Ich trainiere mit LogisticRegression mit LogisticRegression. Die Erklärung der logistischen Regression finden Sie im Artikel "Coursera Machine Learning-Einführungskurs (3. Woche - logistische Regression, Regularisierung)". ・ ・). Dank des Coursera-Einführungskurses für maschinelles Lernen konnte ich mich mit einem Verständnis der Regularisierung nähern.
def train(x_train, y_train, file):
pipline = Pipeline([('vectorizer', myVectorizer()), ('classifier', LogisticRegression())])
In der folgenden Parameterdefinition lautet der Regularisierungsterm "classifier__C" und der Optimierer "classifier__solver". Ich verstehe den Unterschied zwischen Optimierern nicht, aber ich habe ihn nicht mit dem Gefühl untersucht, dass "er durch Rastersuche optimiert werden sollte".
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0004, 0.0005],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #Ich habe auch 10 ausprobiert, aber der SCORE ist niedrig, nur weil er langsam ist
'classifier__solver': ['newton-cg', 'liblinear']},
]
Ich verwende Pipeline, um den Trainingsteil mit Wortvektorisierung und logistischer Regression zu routen. Auf diese Weise können Sie zwei Prozesse gleichzeitig ausführen und gleichzeitig die Hyperparametersuche in der später beschriebenen Rastersuche verarbeiten.
def train(x_train, y_train, file):
pipline = Pipeline([('vectorizer', myVectorizer()), ('classifier', LogisticRegression())])
Ich suche mit [GridSearchCV] nach Hyperparametern (https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html). Da die Pipeline implementiert ist, können sowohl die Wortvektorisierung als auch der Trainingsteil durch logistische Regression gleichzeitig durchsucht werden. Das Suchziel wird durch "PARAMETER" definiert, und der "Zielverarbeitungsname" und der "Parametername" werden durch "__" kombiniert. Tatsächlich gibt es mehr durchsuchbare Parameter, die jedoch weggelassen werden, da die Verarbeitung lange dauert. Dieser Parameter dauert ca. 2 Minuten.
#Parameter für GridSearchCV
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0004, 0.0005],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #Ich habe auch 10 ausprobiert, aber der SCORE ist niedrig, nur weil er langsam ist
'classifier__solver': ['newton-cg', 'liblinear']},
]
#clf steht für Klassifizierung
clf = GridSearchCV(
pipline,
PARAMETERS, #Parametersatz, den Sie optimieren möchten
cv = 5) #Anzahl der Kreuztests
TfidfVectorizer und CountVectorizer /sklearn.feature_extraction.text.CountVectorizer.html) definiert die Klasse "myVectorizer", um herauszufinden, welche die beste ist. Der Vectorizer, der den Parameter method
empfängt und mit dem bedingten Zweig if
verarbeitet, wird geändert. Ich habe auf den folgenden Artikel verwiesen.
class myVectorizer(BaseEstimator, TransformerMixin):
def __init__(self, method='tfidf', min_df=0.0005, max_df=0.10):
self.method = method
self.min_df = min_df
self.max_df = max_df
def fit(self, x, y=None):
if self.method == 'tfidf':
self.vectorizer = TfidfVectorizer(min_df=self.min_df, max_df=self.max_df)
else:
self.vectorizer = CountVectorizer(min_df=self.min_df, max_df=self.max_df)
self.vectorizer.fit(x)
return self
def transform(self, x, y=None):
return self.vectorizer.transform(x)
Das Rastersuchergebnis wird in eine CSV-Datei ausgegeben. Vergleichen wir jedes Kriterium mit den Durchschnitts- und Höchstwerten (unter Verwendung von Excel).
pd.DataFrame.from_dict(clf.cv_results_).to_csv(file)
Ich habe die Parameter etwas erhöht. Daher dauerte das Training ca. 11 Minuten.
#Parameter für GridSearchCV
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0003, 0.0004, 0.0005, 0.0006],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #Ich habe auch 10 ausprobiert, aber der SCORE ist niedrig, nur weil er langsam ist
'classifier__solver': ['newton-cg', 'lbfgs', 'liblinear', 'sag', 'saga']}
]
Der höchste Hyperparameter war eine durchschnittliche korrekte Antwortrate von 75,6% in 5 Kreuzverifizierungen.
Vergleichen wir nun jeden der folgenden Parameter.
TfidfVectorizer/CountVectorizer tf-idf hat eindeutig eine bessere Punktzahl.
min_df Je kleiner die min_df, desto besser die Punktzahl.
max_df Für td-idf ist max_df eine bessere Punktzahl, wenn es weniger ist.
Es gibt keinen großen Unterschied.
Offensichtlich hat 1 eine bessere Punktzahl.