El dataset utilizado es movie_reviews, integrado en NLTK. Contiene 2 000 reseñas, divididas en 1 000 positivas (pos) y 1 000 negativas (neg). Supreme para una introducción equilibrada al análisis de sentimientos.
Para empezar:
import nltk
nltk.obtain('movie_reviews')
from nltk.corpus import movie_reviews # Cargar el dataset
critiques = [(movie_reviews.raw(fileid), category)
for category in movie_reviews.categories()
for fileid in movie_reviews.fileids(category)]
# Previsualizamos un ejemplo
critiques[0][0][:500]
Este paso nos da una primera thought del contenido actual de las reseñas y permite anticipar algunos retos del preprocesamiento: puntuación, saltos de línea, palabras poco significativas…
En NLP, una buena limpieza de datos puede marcar la diferencia. Aquí definí unafunción preprocess() que se encarga de:
- Convertir el texto a minúsculas
- Eliminar saltos de línea y puntuación
- Normalizar espacios
- Tokenizar el texto
- Eliminar stopwords
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
nltk.obtain('punkt')
nltk.obtain('stopwords')
nltk.obtain('punkt_tab')stop_words = stopwords.phrases('english')
def preprocess(texto):
texto = texto.decrease()
texto = texto.exchange('n', ' ')
texto = re.sub(r'[^a-zs]', '', texto)
texto = re.sub(r's+', ' ', texto)
tokens = word_tokenize(texto)
tokens = [word for word in tokens if word not in stop_words]
return ' '.be part of(tokens)
# Aplicar preprocesamiento
processed_reviews = [(preprocess(texto), label) for texto, label in reviews]
Este proceso dejó los textos listos para vectorizarlos y alimentar el modelo.
Con los textos preprocesados, pasamos al modelo. Utilicé CountVectorizer para convertir texto en vectores numéricos y MultinomialNB de sklearn como clasificador.
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.textual content import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report, accuracy_score# Preparar datos
textos, labels = zip(*processed_reviews)
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(textos)
# División practice/check
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.2, random_state=42)
# Entrenar el modelo
mannequin = MultinomialNB()
mannequin.match(X_train, y_train)
# Predicciones
y_pred = mannequin.predict(X_test)
Y finalmente evaluamos el rendimiento:
accuracy_score(y_test, y_pred)
print(classification_report(y_test, y_pred))
En mi caso, obtuve un accuracy superior al 80 % y un F1-score bastante balanceado entre clases. Más que aceptable para un modelo sencillo y sin ajustes avanzados.
Para entender mejor los resultados, me pareció interesante visualizar las palabras más frecuentes en cada tipo de reseña. Usé Counter para contar y seaborn para mostrar los resultados:
import matplotlib.pyplot as plt
import seaborn as sns
from collections import Counterdef plot_most_common_words(label, n=20):
texts = [movie_reviews.raw(fileid) for fileid in movie_reviews.fileids(label)]
full_text = ' '.be part of([preprocess(text) for text in texts])
all_words = full_text.cut up()
freq_dist = Counter(all_words)
common_words = freq_dist.most_common(n)
phrases, freqs = zip(*common_words)
plt.determine(figsize=(10, 6))
sns.barplot(x=record(freqs), y=record(phrases))
plt.title(f'Palabras más frecuentes en reseñas {label}')
plt.xlabel('Frecuencia')
plt.ylabel('Palabra')
plt.present()
plot_most_common_words('pos')
plot_most_common_words('neg')
El resultado de la previsualización y, en este caso, de las reseñas positivas es el siguiente:
Aparte de las palabras básicas de una reseña de una pelicula como movie, film, story, … Se observa que predominan palabras como like, good, properly,… Terminos claramente positivos
Por otro lado, analizando el grafico de las reseñas negativas:
Se observa que en este caso aparecen tambien palabras como dangerous, aunque siguen destacando like y good.