Il s'agit du bilan du 73ème «apprentissage» de 100 langues de traitement knock 2015. Il a fallu beaucoup de temps pour faire des recherches et des essais et erreurs.
Jusqu'à présent, je ne l'ai pas posté sur le blog car c'était fondamentalement la même chose que "Traitement du langage amateur 100 coups". , "Chapitre 8: Machine Learning" a été pris au sérieux et modifié dans une certaine mesure. Je posterai. J'utilise principalement scikit-learn.
Lien | Remarques |
---|---|
073_1.Apprentissage(Prétraitement).ipynb | Programmederéponse(Prétraitement編)Lien GitHub |
073_2.Apprentissage(Entraînement).ipynb | Programmederéponse(Entraînement編)Lien GitHub |
100 coups de traitement du langage amateur:73 | Je vous suis toujours redevable de 100 coups de traitement linguistique |
Introduction à Python avec 100 coups de traitement du langage#73 -Apprentissage automatique, scikit-Retour logistique avec apprentissage | scikit-Résultat Knock en utilisant Learn |
type | version | Contenu |
---|---|---|
OS | Ubuntu18.04.01 LTS | Il fonctionne virtuellement |
pyenv | 1.2.15 | J'utilise pyenv car j'utilise parfois plusieurs environnements Python |
Python | 3.6.9 | python3 sur pyenv.6.J'utilise 9 3.7 ou 3.Il n'y a aucune raison profonde de ne pas utiliser la série 8 Les packages sont gérés à l'aide de venv |
Dans l'environnement ci-dessus, j'utilise les packages Python supplémentaires suivants. Installez simplement avec pip ordinaire.
type | version |
---|---|
nltk | 3.4.5 |
stanfordnlp | 0.2.0 |
pandas | 0.25.3 |
scikit-learn | 0.21.3 |
Dans ce chapitre, [jeu de données de polarité des phrases] de Movie Review Data publié par Bo Pang et Lillian Lee. v1.0](http://www.cs.cornell.edu/people/pabo/movie-review-data/rt-polaritydata.README.1.0.txt) est utilisé pour rendre la phrase positive ou négative. Travaillez sur la tâche (analyse de polarité) à classer comme (négative).
Apprenez le modèle de régression logistique en utilisant les propriétés extraites en> 72.
J'ai utilisé Stanford NLP pour la suppression des mots vides et le traitement de la racine des lemmes, et cela a pris beaucoup de temps, donc je l'ai divisé en prétraitement et apprentissage.
J'utilise tf-idf pour vectoriser les mots. tf-idf calcule l'importance sur la base de deux indicateurs, tf (fréquence du terme) et idf (fréquence inverse du document). Diminuez l'importance des mots (mots généraux) qui apparaissent dans de nombreux documents et augmentez l'importance des mots qui n'apparaissent que dans des documents spécifiques.
Pour être honnête, je ne pouvais pas juger si tf-idf était valide même avec le traitement des mots vides, donc [CountVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer. Comparaison de la vectorisation et de la précision avec la fréquence des mots simples en utilisant html). Nous comparons également les hyperparamètres de régression logistique avec une recherche de grille.
Le premier est le prétraitement. Cependant, ce que nous faisons est [Précédent "Programme de réponse (analyse) 072_2. Extraction d'identité (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) Il n'y a rien de spécial à mentionner. L'inconvénient est que le traitement prend environ une heure.
import warnings
import re
import csv
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer as PS
import stanfordnlp
#Défini comme un taple pour la vitesse
STOP_WORDS = set(stopwords.words('english'))
# Stemmer
ps = PS()
#Semble être conforme aux balises Universal POS
# https://universaldependencies.org/u/pos/
EXC_POS = {'PUNCT', #Ponctuation
'X', #Autre
'SYM', #symbole
'PART', #Particule('s etc.)
'CCONJ', #conjonction(et etc.)
'AUX', #Verbe auxiliaire(serait etc.)
'PRON', #Synonyme
'SCONJ', #Connectif subordonné(si etc.)
'ADP', #Conjoint(dans etc.)
'NUM'} #nombre
#Il était lent de spécifier tous les processeurs par défaut, donc réduisez au 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]')
#Suppression des symboles de début et de fin
def remove_symbols(lemma):
return reg_sym.sub('', lemma)
#Arrêter le jugement d'authenticité des mots
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
#Masquer l'avertissement
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 = []
#Les 3 premiers caractères indiquent uniquement négatif / positif, donc n'effectuez pas de traitement nlp(Faites-le aussi vite que possible)
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)])
C'est la partie formation du sujet principal.
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
#Classe d'utilisation de la vectorisation de mots dans 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)
#Paramètres de GridSearchCV
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0004, 0.0005],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #J'ai aussi essayé 10 mais le SCORE est faible juste parce qu'il est lent
'classifier__solver': ['newton-cg', 'liblinear']},
]
#Lire le fichier
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 signifie classification
clf = GridSearchCV(
pipline, #
PARAMETERS, #Jeu de paramètres que vous souhaitez optimiser
cv = 5) #Nombre de tests croisés
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 ou [CountVectorizer](https://scikit-learn.org/stable/modules/generated /sklearn.feature_extraction.text.CountVectorizer.html) est utilisé pour la vectorisation de mots.
C'est un peu déroutant car il est classé de manière à pouvoir être utilisé avec la fonction GridSearchCV
, mais les points importants sont les suivants.
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)
Utilisez fit
pour apprendre de tous les mots et transformer
pour transformer la chaîne de mots.
Les paramètres sont TfidfVectorizer et CountVectorizer. /generated/sklearn.feature_extraction.text.CountVectorizer.html) Les deux utilisent les deux suivants.
--min_df: Si la fréquence d'occurrence est inférieure au rapport spécifié, elle sera exclue de la vectorisation. Il est précisé car on considère que "l'apprentissage n'est pas possible si la fréquence d'apparition est trop faible". --max_df: Exclut de la vectorisation si elle se produit plus fréquemment que le pourcentage spécifié. Cette fois, j'ai pensé que "des mots comme" film "n'ont aucun sens" et je l'ai précisé.
Je m'entraîne avec LogisticRegression en utilisant LogisticRegression. L'explication de la régression logistique est écrite dans l'article "Coursera Machine Learning Introduction Course (3ème semaine-Régression logistique, régression)". ・ ・). Grâce au Cours d'introduction à l'apprentissage automatique de Coursera, j'ai pu aborder avec une compréhension de la régularisation.
def train(x_train, y_train, file):
pipline = Pipeline([('vectorizer', myVectorizer()), ('classifier', LogisticRegression())])
Dans la définition de paramètre suivante, le terme de régularisation est classifier__C
et l'optimiseur est classifier__solver
. Je ne comprends pas la différence entre les optimiseurs, mais je ne l'ai pas étudié avec le sentiment qu '"il devrait être optimisé par une recherche de grille".
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0004, 0.0005],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #J'ai aussi essayé 10 mais le SCORE est faible juste parce qu'il est lent
'classifier__solver': ['newton-cg', 'liblinear']},
]
J'utilise Pipeline pour canaliser la partie formation avec vectorisation de mots et régression logistique. En conséquence, deux processus peuvent être exécutés en même temps, et la recherche d'hyper paramètre dans la recherche de grille décrite plus loin peut également être traitée en même temps.
def train(x_train, y_train, file):
pipline = Pipeline([('vectorizer', myVectorizer()), ('classifier', LogisticRegression())])
Je recherche des hyper paramètres en utilisant GridSearchCV. Puisque le pipeline est implémenté, le mot vectorisation et la partie formation par régression logistique peuvent être recherchées en même temps. La cible de recherche est définie par «PARAMETERS», et le «nom de traitement cible» et le «nom de paramètre» sont combinés par «__». En fait, il existe davantage de paramètres de recherche, mais ils sont omis car le traitement prend beaucoup de temps. Ce paramètre prend environ 2 minutes.
#Paramètres de GridSearchCV
PARAMETERS = [
{
'vectorizer__method':['tfidf', 'count'],
'vectorizer__min_df': [0.0004, 0.0005],
'vectorizer__max_df': [0.07, 0.10],
'classifier__C': [1, 3], #J'ai aussi essayé 10 mais le SCORE est faible juste parce qu'il est lent
'classifier__solver': ['newton-cg', 'liblinear']},
]
#clf signifie classification
clf = GridSearchCV(
pipline,
PARAMETERS, #Jeu de paramètres que vous souhaitez optimiser
cv = 5) #Nombre de tests croisés
TfidfVectorizer et [CountVectorizer](https://scikit-learn.org/stable/modules/generated /sklearn.feature_extraction.text.CountVectorizer.html) définit la classe myVectorizer
pour savoir laquelle est la meilleure. Le Vectorizer qui reçoit le paramètre «method» et le traite dans la branche conditionnelle «if» est modifié. J'ai fait référence à l'article suivant.
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)
Le résultat de la recherche de grille est généré dans un fichier CSV. Comparons chaque critère avec les scores moyens et maximum (en utilisant Excel).
pd.DataFrame.from_dict(clf.cv_results_).to_csv(file)
J'ai un peu augmenté les paramètres. Par conséquent, la formation a duré environ 11 minutes.
#Paramètres de 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], #J'ai aussi essayé 10 mais le SCORE est faible juste parce qu'il est lent
'classifier__solver': ['newton-cg', 'lbfgs', 'liblinear', 'sag', 'saga']}
]
L'hyper paramètre le plus élevé était un taux moyen de réponses correctes de 75,6% dans 5 vérifications croisées.
Maintenant, comparons chaque paramètre ci-dessous.
TfidfVectorizer/CountVectorizer tf-idf a clairement un meilleur score.
min_df Plus le min_df est petit, meilleur est le score.
max_df Pour td-idf, max_df est un meilleur score s'il est inférieur.
Il n'y a pas beaucoup de différence.
De toute évidence, 1 a un meilleur score.
Recommended Posts