Technologie

Classification des sentiments avec traitement du langage naturel sur LSTM

Classification des sentiments avec traitement du langage naturel sur LSTM


Google
Ainsi, l'analyse sémantique latente (LSA) est une théorie et une méthode permettant d'extraire et de représenter le sens de l'utilisation contextuelle de mots par des calculs statistiques appliqués à un grand corpus de texte. LSA est une technique de récupération d'informations qui analyse et identifie le motif dans une collection de texte non structurée et la relation entre eux.

LSA est un moyen non supervisé de découvrir des synonymes dans une collection de documents. Commençons par examiner comment l'analyse sémantique latente est utilisée dans le traitement du langage naturel pour analyser les relations entre un ensemble de documents et les termes qu'ils contiennent. Ensuite, nous allons plus loin pour analyser et classer les sentiments. Nous examinerons Chi Squared pour la sélection des fonctionnalités en cours de route. Nous utiliserons des réseaux de neurones récurrents, et en particulier des LSTM, pour effectuer une analyse de sentiment dans Keras. Commençons!

importer des pandas en tant que pd
df = pd.read_csv ('Reviews.csv')
df.head ()
Amazon Food Review

Prétraitement du texte

Étant donné que le texte est la forme la plus non structurée de toutes les données disponibles, différents types de bruit y sont présents et les données ne sont pas facilement analysables sans traitement préalable. Le processus complet de nettoyage et de normalisation du texte, le rendant sans bruit et prêt à être analysé, est appelé prétraitement du texte.

Il est principalement composé des étapes suivantes:

Tout morceau de texte qui n'est pas pertinent pour le contexte des données et la sortie finale peut être spécifié en tant que bruit.

Par exemple, les mots vides (mots couramment utilisés dans une langue) sont, par exemple, les URL, les liens, les entités de médias sociaux (mentions, hashtags), les ponctuations et les mots spécifiques à l’industrie. Cette étape traite de la suppression de tous les types d’entités bruyantes présentes dans le texte.

Une approche générale pour la suppression du bruit consiste à préparer un dictionnaire des entités bruitées et à itérer l’objet texte avec des jetons (ou des mots), en éliminant les jetons présents dans le dictionnaire de bruit.

Un autre type de bruit textuel concerne les représentations multiples présentées par un seul mot.

Par exemple, “jouer”, “joueur”, “joué”, “jouer” et “jouer” sont les différentes variantes du mot - “jouer”, bien qu’ils aient une signification différente mais que leur contexte soit semblable. L'étape convertit toutes les disparités d'un mot dans leur forme normalisée (également appelée lemme). La normalisation est une étape cruciale pour l’ingénierie des caractéristiques avec le texte, car elle convertit les entités de grande dimension (N entités différentes) en un espace de petite dimension (1 entité), ce qui est idéal pour tous les modèles ML.

Les pratiques de normalisation de lexique les plus courantes sont les suivantes:

  • Racine: La tige est un processus rudimentaire, basé sur des règles, consistant à supprimer les suffixes («ing», «ly», «es», «s», etc.) d'un mot.
  • Lemmatisation: La lemmatisation, quant à elle, est une procédure organisée et pas à pas pour obtenir la forme racine du mot. Elle utilise le vocabulaire (importance du dictionnaire dans les mots) et l'analyse morphologique (structure des mots et relations grammaticales).
  • Arrêtez la suppression de mot

La suppression du mot d'arrêt est une étape de prétraitement importante pour certaines applications PNL, telles que l'analyse des sentiments, la synthèse de texte, etc.

La suppression des mots vides, ainsi que la suppression des mots courants, est une étape fondamentale mais importante. Ce qui suit est une liste de mots vides qui vont être supprimés. Cette liste a été générée à partir de nltk.

# Nettoyage des textes
import re
importer nltk
nltk.download ('mots vides')
de nltk.corpus importer des mots vides
de nltk.stem.porter importer PorterStemmer
corpus = []
pour i dans la plage (0, 10000):
review = re.sub ('[^a-zA-Z]',' ', df['Text'][i])
review = review.lower ()
review = review.split ()
ps = PorterStemmer ()
review = [ps.stem(word) for word in review if not word in set(stopwords.words('english'))]
review = '' .join (review)
corpus.append (revue)

Caractéristiques statistiques

Les données texte peuvent également être quantifiées directement en chiffres à l'aide de plusieurs techniques décrites dans cette section:

A. Fréquence de terme - Fréquence de document inverse (TF - IDF)

TF-IDF est un modèle pondéré couramment utilisé pour les problèmes d'extraction d'informations. Il vise à convertir les documents texte en modèles vectoriels sur la base de l'occurrence de mots dans les documents sans prendre en compte l'ordre exact. Par exemple, supposons qu'il existe un jeu de données de N documents texte. Dans tout document «D», TF et IDF seront définis comme suit:

Terme Fréquence (TF) - TF pour un terme “t” est défini comme le compte d'un terme “t” dans un document “D”

Fréquence de document inverse (IDF) - IDF pour un terme est défini comme le logarithme du rapport du nombre total de documents disponibles dans le corpus et du nombre de documents contenant le terme T.

TF. IDF - TF La formule IDF donne l'importance relative d'un terme dans un corpus (liste de documents), donnée par la formule suivante ci-dessous. Voici le code qui utilise le paquet scikit learn de python pour convertir un texte en vecteurs tf idf: En d’autres termes, plus le score TFIDF (poids) est élevé, plus le mot est rare, et inversement.

TFIDF
de sklearn.feature_extraction.text importer TfidfVectorizer
tfidf = TfidfVectorizer ()
tfidf.fit (résultat['Reviews'])

Parmi les trois mots «arachide», «jumbo» et «erreur», tf-idf donne le poids le plus élevé à «jumbo». Pourquoi? Cela indique que «jumbo» est un mot beaucoup plus rare que «cacahuète» et «erreur». Voici comment utiliser tf-idf pour indiquer l’importance des mots ou des termes dans une collection de documents.

Classification de sentiment

Pour classer les sentiments, supprimons le score neutre 3, puis les scores de groupe 4 et 5 sur positifs (1), et les scores 1 et 2 sur négatifs (0). Après un simple nettoyage, ce sont les données avec lesquelles nous allons travailler.

result.dropna (inplace = True)
résultat[result['Score'] ! = 3]
résultat['Positivity'] = np.where (résultat['Score'] > 3, 1, 0)
cols = [ 'Score']
result.drop (cols, axis = 1, inplace = True)
result.head ()

Train Test Split

from sklearn.model_selection import train_test_split
X = df.Text
y = df.Positivité
X_train, X_test, y_train, y_test = train_test_split (X, y, random_state = 0)
print ("Le train comprend un total de {0} entrées avec {1: .2f}% négatif, {2: .2f}% positif" .format (len (X_train),
(len (X_train[y_train == 0]) / / len (X_train) * 1.)) * 100,
(len (X_train[y_train == 1]) / (len (X_train) * 1.)) * 100))
print ("L'ensemble de tests contient un total de {0} entrées avec {1: .2f}% négatif, {2: .2f}% positif" .format (len (X_test),
(len (X_test[y_test == 0]) / / len (X_test) * 1.)) * 100,
(len (X_test[y_test == 1]) / (len (X_test) * 1.)) * 100))
1*CHJj uVT9SLEC3ysM3hcGQ - Classification des sentiments avec traitement du langage naturel sur LSTM
1*TURZ hav2L8BMB9zb2091w - Classification des sentiments avec traitement du langage naturel sur LSTM

Vous avez peut-être remarqué que nos classes sont déséquilibrées et que le rapport entre les exemples négatifs et positifs est 22:78.

L'une des tactiques de lutte contre les classes déséquilibrées consiste à utiliser les algorithmes Decision Tree. Nous utilisons donc le classifieur Random Forest pour apprendre les données déséquilibrées et définir class_weight = balancé. Définissez tout d'abord une fonction pour afficher le score de précision.

depuis sklearn.feature_extraction.text importer CountVectorizer
from sklearn.ensemble import RandomForestClassifier
depuis le pipeline d'importation sklearn.pipeline
à partir de sklearn.metrics import precision_score
def precision_summary (pipeline, X_train, y_train, X_test, y_test):
sentiment_fit = pipeline.fit (X_train, y_train)
y_pred = sentiment_fit.predict (X_test)
precision = precision_score (y_test, y_pred)
print ("score d'exactitude: {0: .2f}%". format (exactitude * 100))
retour de précision

Pour avoir une analyse efficace des sentiments ou résoudre tout problème de PNL, nous avons besoin de nombreuses fonctionnalités. Il n'est pas facile de déterminer le nombre exact de fonctionnalités nécessaires. Nous allons donc essayer, 10 000 à 30 000. Et imprimez les scores de précision associés au nombre de fonctionnalités.

cv = CountVectorizer ()
rf = RandomForestClassifier (class_weight = "équilibré")
n_features = np.arange (10000,25001,5000)
def nfeature_accuracy_checker (vectorizer = cv, n_features = n_features, stop_words = Aucun, ngram_range = (1, 1), classificateur = rf):
résultat = []
print (classificateur)
print (" n")
pour n dans n_features:
vectorizer.set_params (stop_words = stop_words, max_features = n, ngram_range = ngram_range)
checker_pipeline = Pipeline ([[
('vectorizer', vectorizer),
('classificateur', classificateur)
])
print ("Résultat du test pour {} caractéristiques" .format (n))
nfeature_accuracy = precision_summary (checker_pipeline, X_train, y_train, X_test, y_test)
result.append ((n, nfeature_accuracy))
résultat retourné
de sklearn.feature_extraction.text importer TfidfVectorizer
tfidf = TfidfVectorizer ()
print ("Résultat pour trigramme avec mots vides (Tfidf) n")
feature_result_tgt = nfeature_accuracy_checker (vectorizer = tfidf, ngram_range = (1, 3))

Avant que nous ayons fini ici, nous devrions vérifier le rapport de classification.

from sklearn.metrics import classification_report
cv = CountVectorizer (max_features = 30000, ngram_range = (1, 3))
pipeline = pipeline ([[
('vectorizer', cv),
('classificateur', rf)
])
sentiment_fit = pipeline.fit (X_train, y_train)
y_pred = sentiment_fit.predict (X_test)
print (classification_report (y_test, y_pred, target_names =['negative','positive']))
rapport de classification

Chi-carré pour la sélection des fonctionnalités

La sélection des fonctionnalités est un problème important dans l’apprentissage automatique. Je vais vous montrer à quel point il est simple d'effectuer une sélection de caractéristiques basée sur le test du chi carré sur notre ensemble de données à grande échelle.

Nous allons calculer les scores du Chi-carré pour toutes les caractéristiques et visualiser les 20 premiers. Ici, les termes ou les mots ou N-grammes sont des caractéristiques et les catégories positive et négative. étant donné une caractéristique X, nous pouvons utiliser le test du chi carré pour évaluer son importance pour distinguer la classe.

from sklearn.feature_selection import chi2
tfidf = TfidfVectorizer (max_features = 30000, ngram_range = (1, 3))
X_tfidf = tfidf.fit_transform (result.Reviews)
y = résultat.Positivité
chi2score = chi2 (X_tfidf, y)[0]
plt.figure (figsize = (16,8))
scores = list (zip (tfidf.get_feature_names (), chi2score))
chi2 = trié (scores, clé = lambda x: x[1])
topchi2 = liste (zip (* chi2[-20:]))
x = plage (len (topchi2[1]))
étiquettes = topchi2[0]
plt.barh (x, topchi2[1], align = 'center', alpha = 0.5)
plt.plot (topchi2[1], x, '-o', taille de marqueur = 5, alpha = 0.8)
plt.yticks (x, étiquettes)
plt.xlabel ('$ chi ^ 2 $')
plt.show ();

Cadre LSTM

depuis sklearn.feature_extraction.text importer CountVectorizer
depuis keras.preprocessing.text import Tokenizer
depuis keras.preprocessing.sequence import pad_sequences
depuis keras.models import Sequential
de keras.layers import Dense, Enrobage, LSTM
from sklearn.model_selection import train_test_split
de keras.utils.np_utils import to_categorical
import re

Séquences de pad

Afin de fournir ces données à notre RNN, tous les documents d'entrée doivent avoir la même longueur. Nous limiterons la longueur maximale des critiques à max_words en tronquant les révisions plus longues et en complétant les révisions plus courtes avec une valeur nulle (0). Nous pouvons accomplir cela en utilisant la fonction pad_sequences () dans Keras. Pour l'instant, définissez max_words. Ensuite, je définis le nombre maximal d'entités à 30000 et utilise Tokenizer pour vectoriser et convertir le texte en séquences afin que le réseau puisse les traiter en entrée.

max_fatures = 30000
tokenizer = Tokenizer (nb_words = max_fatures, split = '')
tokenizer.fit_on_texts (résultat['Reviews'].valeurs)
X1 = tokenizer.texts_to_sequences (résultat['Reviews'].valeurs)
X1 = pad_sequences (X1)
Y1 = pd.get_dummies (résultat['Positivity']).valeurs
X1_train, X1_test, Y1_train, Y1_test = train_test_split (X1, Y1, random_state = 42)
print (X1_train.shape, Y1_train.shape)
print (X1_test.shape, Y1_test.shape)
1*kkYz37Nd0YlfZIplbWmHMA - Classification des sentiments avec traitement du langage naturel sur LSTM

Concevoir un modèle RNN pour l'analyse des sentiments

Nous commençons à construire notre architecture de modèle dans la cellule de code ci-dessous. Nous avons importé de Keras certains calques dont vous pourriez avoir besoin, mais n'hésitez pas à utiliser les autres calques / transformations de votre choix.

Rappelez-vous que notre entrée est une séquence de mots (techniquement, des identifiants de mot entier) de longueur maximale = max_words, et notre sortie est une étiquette de sentiment binaire (0 ou 1).

Keras Inclusion Layer

Keras propose une couche d’incorporation qui peut être utilisée pour les réseaux de neurones sur des données textuelles.

Cela nécessite que les données d'entrée soient codées en entier, afin que chaque mot soit représenté par un entier unique. Cette étape de préparation des données peut être effectuée à l’aide de l’API Tokenizer, également fournie avec Keras.

La couche d’incorporation est initialisée avec des poids aléatoires et apprendra l’intégration de tous les mots du jeu de données d’apprentissage.

C'est une couche flexible qui peut être utilisée de différentes manières, telles que:

  • Il peut être utilisé seul pour apprendre un mot qui peut être enregistré et utilisé ultérieurement dans un autre modèle.
  • Il peut être utilisé dans le cadre d'un modèle d'apprentissage en profondeur où l'intégration est apprise en même temps que le modèle.
  • Il peut être utilisé pour charger un modèle d'intégration de mots pré-formé, un type d'apprentissage par transfert.

La couche d'incorporation est définie comme la première couche masquée d'un réseau. Il doit spécifier 3 arguments:

Il doit spécifier 3 arguments:

  • input_dim: Ceci est la taille du vocabulaire dans les données de texte. Par exemple, si vos données sont codées en nombres entiers avec des valeurs comprises entre 0 et 10, la taille du vocabulaire serait de 11 mots.
  • output_dim: C'est la taille de l'espace vectoriel dans lequel les mots seront incorporés. Il définit la taille des vecteurs de sortie de cette couche pour chaque mot. Par exemple, il pourrait être 32 ou 100 ou même plus grand. Testez différentes valeurs pour votre problème.
  • longueur_entrée: Il s’agit de la longueur des séquences d’entrée que vous définissez pour n’importe quelle couche d’entrée d’un modèle Keras. Par exemple, si tous vos documents d’entrée sont composés de 1 000 mots, ce sera 1 000.

Par exemple, nous définissons ci-dessous une couche d’incorporation avec un vocabulaire de 200 (par exemple, des mots codés en entier de 0 à 199 inclus), un espace vectoriel de 32 dimensions dans lequel des mots seront incorporés et des documents de saisie de 50 mots chacun.

e = incorporation (200, 32, longueur_entrée = 50)

La couche d’incorporation contient des poids qui sont appris. Si vous enregistrez votre modèle dans un fichier, cela inclut les pondérations de la couche d’incorporation. La sortie du Enrobage layer est un vecteur 2D avec une incorporation pour chaque mot dans la séquence de mots en entrée (document en entrée).

Si vous souhaitez connecter un Densecouche directement dans une couche d’incorporation, vous devez d’abord aplatir la matrice de sortie 2D en un vecteur 1D à l’aide de la touche Aplatircouche.

embed_dim = 150
lstm_out = 200
modèle = séquentiel ()
model.add (Incorporation (max_fatures, embed_dim, input_length = X1.shape)[1], abandon = 0,2))
model.add (LSTM (lstm_out, dropout_U = 0.2, dropout_W = 0.2))
model.add (Dense (2, activation = 'softmax'))
model.compile (loss = 'categorical_crossentropy', optimiseur = 'adam', metrics = ['accuracy'])
print (model.summary ())

Pour résumer, notre modèle est un modèle RNN simple avec 1 couche d'intégration, 1 couche LSTM et 1 couche dense. Au total, 4 781 202 paramètres doivent être formés.

Former et évaluer notre modèle

Nous devons d’abord compiler notre modèle en spécifiant la fonction de perte et l’optimiseur que nous voulons utiliser pendant la formation, ainsi que toute mesure d’évaluation que nous souhaitons mesurer. Spécifiez les paramètres appropriés, y compris au moins une métrique «précision».

batch_size = 32
model.fit (X1_train, Y1_train, nb_epoch = 3, batch_size = batch_size, verbose = 2)

Une fois compilé, nous pouvons lancer le processus de formation. Nous devons spécifier deux paramètres de formation importants: la taille du lot et le nombre d'époques de formation, qui, avec notre architecture de modèle, déterminent le temps total de formation.

score, acc = model.evaluate (X1_test, Y1_test, verbose = 2, batch_size = batch_size)
print ("score:% .2f"% (score))
print ("acc:% .2f"% (acc))
score: 0.51
acc: 0,84

Enfin, mesurer le nombre de suppositions correctes. Il est clair que la recherche de tweets négatifs va très bien pour le réseau, mais décider si elle est positive ne l’est pas vraiment.

pos_cnt, neg_cnt, pos_correct, neg_correct = 0, 0, 0, 0
pour x dans la plage (len (X1_test)):

resultat = model.predict (X1_test[x].reshape (1, X1_test.shape[1]), batch_size = 1, verbose = 2)[0]

si np.argmax (résultat) == np.argmax (Y1_test[x]):
si np.argmax (Y1_test[x]) == 0:
neg_correct + = 1
autre:
pos_correct + = 1

si np.argmax (Y1_test[x]) == 0:
neg_cnt + = 1
autre:
pos_cnt + = 1

print ("pos_acc", pos_correct / pos_cnt * 100, "%")
print ("neg_acc", neg_correct / neg_cnt * 100, "%")

pos_acc 90.67439409905164%
neg_acc 63.2890365448505%

Résumé

Nous pouvons construire notre modèle de plusieurs manières. Nous pouvons continuer d'essayer et d'améliorer la précision de notre modèle en expérimentant avec différentes architectures, couches et paramètres. Comment pouvons-nous obtenir sans prendre trop de temps pour nous entraîner? Comment pouvons-nous prévenir l'overfitting?

C'est tout pour aujourd'hui. Le code source peut être trouvé sur Github. Je suis heureux d'entendre des questions ou des commentaires. Connectez-vous avec moi à Linkdin.

Show More

SupportIvy

SupportIvy.com : Un lieu pour partager le savoir et mieux comprendre le monde. Meilleure plate-forme de support gratuit pour vous, Documentation &Tutoriels par les experts.

Related Articles

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Close
Close