Procesamiento de lenguaje natural¶

Análisis de sentimientos¶

Proyecto¶



Autor: Luis Fernando Apáez Álvarez



Desglose de temas¶

  • Regresión logística
  • División de datos y métricas para la evaluación
  • Proyecto 0



Dentro de esta clase utilizaremos un modelo de aprendizaje supervisado para predecir el sentimiento. Para ello, supongamos que estamos trabajando con las reseñas de ciertos productos, así como el conjunto de datos con el cual trabajamos sobre reseñas de productos vendidos en amazon. Una tarea de aprendizaje supervisado intentará clasificar cualquier reseña nueva como una positiva o negativa, según la información de las reseñas clasificadas que ya tenemos. De modo que el tipo de problema es de clasificación, donde, dado que tenemos dos etiquetas (positivo y negativo), entonces es un problema de clasificación binaria.

Un algorítmo que se utiliza comúnmente en las tareas de clasificación es una regresión logística

Recordemos que en la regresión lineal, ajustamos una recta para aproximar una relación. En su lugar, en una regresión logística estamos ajustando una curva "s", denominada también función sigmoidea. Otro punto de comparativa es que, en la regresión lineal, estamos prediciendo un resultado numérico continuo, pero con la regresión logística, estimamos la probabilidad de que el resultado pertenezca a la categoría 1 o a la categoría 2. En el caso de nuestro ejemplo, estimaríamos la probabilidad:

$$ P(sentimiento=positivo\ |\ reseña ) \ \ \ \ \ \textrm{y} \ \ \ \ \ P(sentimiento=negativo\ |\ reseña ) $$

Dado que estamos estimando una probabilidad y queremos que el resultado estén entre el 0 y el 1, modelamos los valores de $x$ utilizando la función sigmoidea. Por ejemplo, si en una reseña tenemos una probabilidad estimada de 0.7, lo cual redondeamos a 1, podremos decir entonces que el sentimiento es positivo (donde configuramos que el 1 está asociado a que el sentimiento es positivo y que el 0 está asociado con el sentimiento negativo); del mismo modo, si, dada una reseña, tenemos que la probabilidad estimada es de 0.2, que redondea a 0, podremos decir que el sentimiento predicho es de negativo.

Para utiliza la regresión logística en Python, escribimos


# Importacion necesaria
from sklearn.linear_model import LogisticRegression

# Mandamos a llamar a la funcion de regresion logistica
# y creamos un objeto clasificador logistico.
# Ademas, ajustamos el modelo para las variables previamente
# definidas X y y
log_reg = LogisticRegression().fit(X,y)

donde X corresponde a las características o variables regresoras y y corresponde a la variable objetivo (que es la etiqueta negativo o positivo), donde en ambas variables éstas son arrays numpy.

Por otro lado, cómo podremos saber si nuestro modelo es bueno. Para ello veremos la diferencia entre el valor real y el valor predicho, donde previamente separamos nuestros datos en un conjunto de entrenamiento y uno de pruebas. Así, si evaluamos nuestro modelo sobre el conjunto de pruebas, podemos comparar los valores predichos con los valores reales, lo cual nos dará un indicio de qué tan bien está funcionando el modelo. Una buena métrica para evaluar un modelo es la precisión (accuracy), la cual se obtiene de considerar la fracción entre las predicciones que el modelo acertó contra el total de predicciones. Así, si la precisión es cercana a uno, tenemos indicios de que nuestro modelo es bueno.

Una manera de calcular la precisión es:


log_reg = LogisticRegression().fic(X,y)

# Precicion/puntuacion
score = log_reg.score(X, y)
print(score)

De manera alternativa


# Importacion necesaria
from sklearn.metrics import accuracy_score

# Requerimos calcular las predicciones
y_pred = log_reg.predict(X)

# Evaluacion del modelo mediante la precision
accuracy = accuracy_score(y, y_pred)

donde dicha función dará un tipo de métrica dependiendo del modelo que se use.

Ahora bien, lo que se hará será dividir los datos en un conjunto de entrenamiento, el cual nos servirá, justamente, para entrenar al modelo; tendremos también un conjunto de pruebas para ver si el modelo entrenado funciona bien en datos nuevos con los cuales no ha trabajado. Para ello escribimos


# Importacion necesaria
from sklearn.model_selection import train_test_split

# train_test_split toma como argumento matrices, listas o dataframes
X_train, y_train, X_test, y_test = train_test_split(X, y,
                                                    test_size=0.2,
                                                    random_state=123,
                                                    stratify=y)

donde stratify nos permite asegurarnos de que el conjunto de entrenamiento y de pruba tengan proporciones similares de ambas muestras. Luego, podemos obtener el valor de precisión del modelo para los datos de entrenamiento y para los datos de prueba. Es claro que la presición para los datos de prueba es menor a la presición para los datos de entrenamiento.

Otra forma de medir y ver el desempeño de un modelo es mediante la matriz de confusión

. Valor real = 1 Valor real = 0
Predicción = 1 Verdadero positivo Falso positivo
Predicción = 0 Falso negativo Verdadero negativo

donde:

  • Verdadero positivo es el número de instancias correctamente etiquetadas con la etiqueta 1.
  • Falso positivo es un valor de etiqueta 0, etiquetado erronéamente con el 1.
  • Falso negativo es un valor de etiqueta 1, etiquetado erronéamente con el 0.
  • Verdadero negativo es el número de instancias correctamente etiquetadas con la etiqueta 0.

En Python podemos utilizar la matriz de confusión escribiendo


# Importacion necesaria
from sklearn.metrica import confusion_matrix

# Construccion de la regresion logistica y prediccion de las
# etiquetas en el conjunto de prueba
log_reg = LogisticRegression().fic(X_train, y_train)
y_pred = log_reg.predict(X_train)

# Matriz de confusion
print(confusion_matrix(y_test, y_pred) / len(y_test))

### Ejemplo de salida
[[0.3782 0.1222]
 [0.1351 0.3635]]

lo cual nos arrojará proporciones en las celdas de la matriz y donde:

  • Proporción de verdadero positivo: 0.3782
  • Proporción de falso positivo: 0.1222
  • Proporción de falso negativo: 0.1351
  • Proporción de verdadero negativo: 0.3635

Ahora bien, para poder emplear el modelo de regresión logística usando como características textos, así como las reseñas, deberemos de transformar los campos de texto en columnas numéricas, lo cual nos daría como resultado muchas características, lo cual puede hacer que el modelo sea bastante complejo. Un modelo complejo puede ocurrir en algunos escenarios:

  • Si usamos una función muy complicada para explicar la relación de interés, lo cual provoca cierto ruido en los datos (sobreentrenamiento)
  • Si tenemos demasiadas características y parámetros innecesarios.

Una forma de evitar los modelos complejos es mediante la regularización, donde estaremos penalizando o restringiendo la función del modelo. Ésta se aplica de manera predeterminada en la función de regresión logística de sklearn.

Proyecto 0¶

Recapitulación¶

  • Exploramos las reseñas en el conjunto de datos referente a las reseñas de películas.
  • Creamos una nube de palabras para ver rápidamente cuáles son las palabras que se menciona con más frecuencia en las críticas positivas o negativas.
  • Creamos características para la longitud de una reseña en términos del número de palabras y oraciones, es decir, agregamos características adicionales a las que ya teníamos.
  • Aprendimos a detectar el idioma de un documento.
  • Realizamos transformaciones numéricas de las características de las reseñas, lo cual hicimos mediante los distintos enfoques como la bolsa de palabras o el algoritmo tf-idf.
  • Aprendimos sobre lemas y derivadores.
  • Utilizamos la regresión logística para entrenar un clasificador que predice el sentimiento.

Implementaremos todo lo anterior para las reseñas de productos de amazon, para ello:

  1. Comenzamos por cargar los datos
In [1]:
import pandas as pd
data = pd.read_csv('amazon_reviews_sample.csv')[['score', 'review']]
data.head()
Out[1]:
score review
0 1 Stuning even for the non-gamer: This sound tr...
1 1 The best soundtrack ever to anything.: I'm re...
2 1 Amazing!: This soundtrack is my favorite musi...
3 1 Excellent Soundtrack: I truly like this sound...
4 1 Remember, Pull Your Jaw Off The Floor After H...
In [2]:
data
Out[2]:
score review
0 1 Stuning even for the non-gamer: This sound tr...
1 1 The best soundtrack ever to anything.: I'm re...
2 1 Amazing!: This soundtrack is my favorite musi...
3 1 Excellent Soundtrack: I truly like this sound...
4 1 Remember, Pull Your Jaw Off The Floor After H...
... ... ...
9995 1 A revelation of life in small town America in...
9996 1 Great biography of a very interesting journal...
9997 0 Interesting Subject; Poor Presentation: You'd...
9998 0 Don't buy: The box looked used and it is obvi...
9999 1 Beautiful Pen and Fast Delivery.: The pen was...

10000 rows × 2 columns

In [3]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   score   10000 non-null  int64 
 1   review  10000 non-null  object
dtypes: int64(1), object(1)
memory usage: 156.4+ KB

Consideraremos un filtrado de datos para las reseñas positivas

In [15]:
data_positive = pd.DataFrame(data[data.score == 1].review)
data_positive
Out[15]:
review
0 Stuning even for the non-gamer: This sound tr...
1 The best soundtrack ever to anything.: I'm re...
2 Amazing!: This soundtrack is my favorite musi...
3 Excellent Soundtrack: I truly like this sound...
4 Remember, Pull Your Jaw Off The Floor After H...
... ...
9990 Psychological thriller!: This movie really sc...
9991 A little more money than what I expected to s...
9995 A revelation of life in small town America in...
9996 Great biography of a very interesting journal...
9999 Beautiful Pen and Fast Delivery.: The pen was...

4903 rows × 1 columns

In [18]:
# Veamos la primer resegnia
data_positive.iloc[0][0]
Out[18]:
' Stuning even for the non-gamer: This sound track was beautiful! It paints the senery in your mind so well I would recomend it even to people who hate vid. game music! I have played the game Chrono Cross but out of all of the games I have ever played it has the best music! It backs away from crude keyboarding and takes a fresher step with grate guitars and soulful orchestras. It would impress anyone who cares to listen! ^_^\r\n'
  1. Realizamos una pequeña limpieza en los datos, para cada fila del dataframe anterior
In [24]:
import re

# Patron de busqueda
# Quitamos los <br> /><br> /> o quitamos todos los caracteres que no son
# alfanumericos o todos los guiones bajos
pattern = re.compile(r'<br /><br />|[^\w]|_')

# Sustituimos todos los <br /><br /> por espacios en blanco
data_positive.review = data_positive.review.apply(lambda x: pattern.sub(' ', x))

# Veamos la primer resegnia
data_positive.iloc[0][0]
Out[24]:
' Stuning even for the non gamer  This sound track was beautiful  It paints the senery in your mind so well I would recomend it even to people who hate vid  game music  I have played the game Chrono Cross but out of all of the games I have ever played it has the best music  It backs away from crude keyboarding and takes a fresher step with grate guitars and soulful orchestras  It would impress anyone who cares to listen       '
In [26]:
data_positive.iloc[1][0]
Out[26]:
' The best soundtrack ever to anything   I m reading a lot of reviews saying that this is the best  game soundtrack  and I figured that I d write a review to disagree a bit  This in my opinino is Yasunori Mitsuda s ultimate masterpiece  The music is timeless and I m been listening to it for years now and its beauty simply refuses to fade The price tag on this is pretty staggering I must say  but if you are going to buy any cd for this much money  this is the only one that I feel would be worth every penny   '

Convertimos y unimos todas las resegnias positivas en un solo string

In [29]:
positive_reviews = ' '
for i in range(len(data_positive)):
    positive_reviews += data_positive.iloc[i][0]
positive_reviews[:1000]
Out[29]:
'  Stuning even for the non gamer  This sound track was beautiful  It paints the senery in your mind so well I would recomend it even to people who hate vid  game music  I have played the game Chrono Cross but out of all of the games I have ever played it has the best music  It backs away from crude keyboarding and takes a fresher step with grate guitars and soulful orchestras  It would impress anyone who cares to listen        The best soundtrack ever to anything   I m reading a lot of reviews saying that this is the best  game soundtrack  and I figured that I d write a review to disagree a bit  This in my opinino is Yasunori Mitsuda s ultimate masterpiece  The music is timeless and I m been listening to it for years now and its beauty simply refuses to fade The price tag on this is pretty staggering I must say  but if you are going to buy any cd for this much money  this is the only one that I feel would be worth every penny    Amazing   This soundtrack is my favorite music of all tim'
In [30]:
len(positive_reviews)
Out[30]:
2112327

Luego, quitaremos el exceso de espacios en blanco

In [35]:
# Si aparace un espacio en blanco una o mas veces
pattern = re.compile(r' +')
# lo sustituiremos por solo un espacio en blanco
positive_reviews2 = pattern.sub(' ', positive_reviews)
positive_reviews2[:1000]
Out[35]:
' Stuning even for the non gamer This sound track was beautiful It paints the senery in your mind so well I would recomend it even to people who hate vid game music I have played the game Chrono Cross but out of all of the games I have ever played it has the best music It backs away from crude keyboarding and takes a fresher step with grate guitars and soulful orchestras It would impress anyone who cares to listen The best soundtrack ever to anything I m reading a lot of reviews saying that this is the best game soundtrack and I figured that I d write a review to disagree a bit This in my opinino is Yasunori Mitsuda s ultimate masterpiece The music is timeless and I m been listening to it for years now and its beauty simply refuses to fade The price tag on this is pretty staggering I must say but if you are going to buy any cd for this much money this is the only one that I feel would be worth every penny Amazing This soundtrack is my favorite music of all time hands down The intense sa'
In [36]:
len(positive_reviews2)
Out[36]:
2044858
  1. Creamos una nube de palabras
In [38]:
# Importacion necesaria
from wordcloud import WordCloud
import matplotlib.pyplot as plt
plt.figure(figsize=(10,6))

# Instanciamos un objeto WordCloud cambiando el color de fondo
# y actuando sobre las resegnias positivas limpias
cloud_positive = WordCloud(background_color='white').generate(positive_reviews2)

# Graficamos
plt.imshow(cloud_positive, interpolation='bilinear')
# Configuramos que los ejes no sean visibles
plt.axis('off')
plt.show()

Notamos varias palabras referentes a las reseñas positivas, notamos que la palabra book es la que más aparece, de modo que la mayoría de las reseñas son de libros. Lo que haremos después será quitar las palabras vacías y añadiremos a éstas las palabras book, song, people, product, video

In [44]:
# Importamos ademas la lista predefinida de palabras vacias
# del ingles de sklearn
from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS

# Podemos enriquecer, o agregar, mas palabras vacias a la lista predefinida
# de las palabras vacias de sklearn, por ejemplo:
stop_words = ENGLISH_STOP_WORDS.union(['book', 'song',' people', 'product', 
                                       'video', 'movie', 'read', 'music',
                                       'CD', 'film', 'song', 'DVD',
                                      'album', 'day', 'books', 'time'])

# Instanciamos un objeto WordCloud cambiando el color de fondo
# y actuando sobre las resegnias positivas limpias
cloud_positive = WordCloud(background_color='white', 
                           stopwords=stop_words).generate(positive_reviews2)

# Graficamos
plt.figure(figsize=(10, 6))
plt.imshow(cloud_positive, interpolation='bilinear')
# Configuramos que los ejes no sean visibles
plt.axis('off')
plt.show()

lo cual nos da una mejor perspectiva de las palabras que más aparecen en las reseñas positivas

  1. Creamos caractéristicas nuevas, como tokenización y longitud de las reseñas. Comenzamos por ver de nuevo los datos
In [45]:
data_positive.head()
Out[45]:
review
0 Stuning even for the non gamer This sound tr...
1 The best soundtrack ever to anything I m re...
2 Amazing This soundtrack is my favorite musi...
3 Excellent Soundtrack I truly like this sound...
4 Remember Pull Your Jaw Off The Floor After H...

Después, tokenizaremos cada reseña

In [53]:
# Importacion necesaria
from nltk.corpus.reader.tagged import word_tokenize
# Ejemplo
word_tokenize('hello how are you'.lower())
Out[53]:
['hello', 'how', 'are', 'you']
In [54]:
# Tokenizacion
data_positive['tokens'] = data_positive.review.apply(lambda x: word_tokenize(x.lower()))
data_positive.head()
Out[54]:
review tokens tokens_lemm
0 Stuning even for the non gamer This sound tr... [stuning, even, for, the, non, gamer, this, so... [Stuning, even, for, the, non, gamer, This, so...
1 The best soundtrack ever to anything I m re... [the, best, soundtrack, ever, to, anything, i,... [The, best, soundtrack, ever, to, anything, I,...
2 Amazing This soundtrack is my favorite musi... [amazing, this, soundtrack, is, my, favorite, ... [Amazing, This, soundtrack, is, my, favorite, ...
3 Excellent Soundtrack I truly like this sound... [excellent, soundtrack, i, truly, like, this, ... [Excellent, Soundtrack, I, truly, like, this, ...
4 Remember Pull Your Jaw Off The Floor After H... [remember, pull, your, jaw, off, the, floor, a... [Remember, Pull, Your, Jaw, Off, The, Floor, A...

Luego, lematizaremos cada token:

In [55]:
# Importacion necesaria
from nltk.stem import WordNetLemmatizer

# Instanciamos
lemattizer = WordNetLemmatizer()

# Crearemos una funcion auxiliar
def lematizar(tokens):
    tokens_lemmatizados = []
    for token in tokens:
        tokens_lemmatizados.append(lemattizer.lemmatize(token))
    return tokens_lemmatizados

# Creamos una columna nueva con los tokens lematizados
data_positive['tokens_lemm'] = data_positive.tokens.apply(lambda x: lematizar(x))
data_positive.head()
Out[55]:
review tokens tokens_lemm
0 Stuning even for the non gamer This sound tr... [stuning, even, for, the, non, gamer, this, so... [stuning, even, for, the, non, gamer, this, so...
1 The best soundtrack ever to anything I m re... [the, best, soundtrack, ever, to, anything, i,... [the, best, soundtrack, ever, to, anything, i,...
2 Amazing This soundtrack is my favorite musi... [amazing, this, soundtrack, is, my, favorite, ... [amazing, this, soundtrack, is, my, favorite, ...
3 Excellent Soundtrack I truly like this sound... [excellent, soundtrack, i, truly, like, this, ... [excellent, soundtrack, i, truly, like, this, ...
4 Remember Pull Your Jaw Off The Floor After H... [remember, pull, your, jaw, off, the, floor, a... [remember, pull, your, jaw, off, the, floor, a...

y obtenemos la longitud de cada lista de tokens

In [56]:
# Creamos una columna nueva con la longitud de cada lista de tokens
data_positive['long'] = data_positive.tokens.apply(lambda x: len(x))
data_positive.head()
Out[56]:
review tokens tokens_lemm long
0 Stuning even for the non gamer This sound tr... [stuning, even, for, the, non, gamer, this, so... [stuning, even, for, the, non, gamer, this, so... 80
1 The best soundtrack ever to anything I m re... [the, best, soundtrack, ever, to, anything, i,... [the, best, soundtrack, ever, to, anything, i,... 102
2 Amazing This soundtrack is my favorite musi... [amazing, this, soundtrack, is, my, favorite, ... [amazing, this, soundtrack, is, my, favorite, ... 136
3 Excellent Soundtrack I truly like this sound... [excellent, soundtrack, i, truly, like, this, ... [excellent, soundtrack, i, truly, like, this, ... 122
4 Remember Pull Your Jaw Off The Floor After H... [remember, pull, your, jaw, off, the, floor, a... [remember, pull, your, jaw, off, the, floor, a... 90
In [60]:
data_positive.sort_values('long')[['review', 'long']]
Out[60]:
review long
881 Good read ... 4
8887 First Knight Cassette Excellent service p... 15
7654 Question of thought How would Nietzsche crit... 15
7932 excellent Original fun breathless ... 15
7951 great subsitute for sony memory stick Great ... 16
... ... ...
2271 It ll get in your head I saw the video f... 203
6576 I love it Ray J has soul I love this cd so ... 205
303 Fun To Listen To This is the second best Ca... 208
4313 Has Streisand stayed too long at the fair NO... 208
8257 cabin worthy Live in New Mexico and have a s... 215

4903 rows × 2 columns

  1. Construiremos ahora un vectorizador utilizando para ello el algoritmo tf-idf
In [63]:
import warnings
warnings.filterwarnings('ignore')

from sklearn.feature_extraction.text import TfidfVectorizer

# Construimos el vectorizador configuramos el set de las palabras
# vacias que ya teniamos. Tambien, configuramos la consideracion de 
# unigramas y bigramas. Establecemos un maximo de frecuencia 
# para las caracteristicas de termino. Y ajustamos sobre todas las 
# resegnias
vect = TfidfVectorizer(stop_words=stop_words, ngram_range=(1,2),
                      max_features=200).fit(data.review)

# Creamos la matriz dispersa
X = vect.transform(data.review)

# Creamos un dataframe 
reviews_transformed = pd.DataFrame(X.toarray(), columns=vect.get_feature_names())
reviews_transformed.head()
Out[63]:
10 able acting action actually ago amazing amazon author away ... work works world worst worth writing written wrong year years
0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.296352 ... 0.000000 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0 0.000000
1 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.000000 ... 0.000000 0.0 0.0 0.0 0.224690 0.0 0.0 0.0 0.0 0.213913
2 0.0 0.0 0.0 0.0 0.0 0.0 0.432583 0.0 0.0 0.000000 ... 0.161535 0.0 0.0 0.0 0.180921 0.0 0.0 0.0 0.0 0.172243
3 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.000000 ... 0.000000 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0 0.000000
4 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.000000 ... 0.000000 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0 0.000000

5 rows × 200 columns

  1. Ahora, lo que haremos será construir un clasificador utilizando para ello regresión logística. Antes de ello agregaremos una columna nueva al dataframe anterior para colocar el valor de la columna score del dataframe original.

Notemos que los siguientes dataframes tienen el mismo número de filas

In [65]:
reviews_transformed.shape
Out[65]:
(10000, 200)
In [66]:
data.shape
Out[66]:
(10000, 2)

Esto es, las filas de las reseñas son respetadas, así, hacemos la asignación del score como sigue

In [67]:
data.score
Out[67]:
0       1
1       1
2       1
3       1
4       1
       ..
9995    1
9996    1
9997    0
9998    0
9999    1
Name: score, Length: 10000, dtype: int64
In [68]:
reviews_transformed['score'] = data.score
reviews_transformed.head()
Out[68]:
10 able acting action actually ago amazing amazon author away ... works world worst worth writing written wrong year years score
0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.296352 ... 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0 0.000000 1
1 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.000000 ... 0.0 0.0 0.0 0.224690 0.0 0.0 0.0 0.0 0.213913 1
2 0.0 0.0 0.0 0.0 0.0 0.0 0.432583 0.0 0.0 0.000000 ... 0.0 0.0 0.0 0.180921 0.0 0.0 0.0 0.0 0.172243 1
3 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.000000 ... 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0 0.000000 1
4 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.000000 ... 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0 0.000000 1

5 rows × 201 columns

Continuando

In [107]:
# Importacion necesaria
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.linear_model import LogisticRegression

# Definimos las variables en cuestion
y = np.array(reviews_transformed.score).reshape(-1, 1)
X = np.array(reviews_transformed.drop('score', axis=1))

# Hacemos la division de los datos
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=0.2, random_state=123) 
# Entrenamos un modelo de regresion logistica
log_reg = LogisticRegression().fit(X_train, y_train)

# Realizamos la prediccion de las etiquetas
y_pred = log_reg.predict(X_test)

# Imprimimos la puntuacion de precision y la matriz de confusion
print('Precisión del modelo en el conjunto de prueba: ', accuracy_score(y_test, y_pred))
print()
print(confusion_matrix(y_test, y_pred) / len(y_test))
Precisión del modelo en el conjunto de prueba:  0.794

[[0.414  0.1005]
 [0.1055 0.38  ]]

Probemos nuestro clasificador, para lo cual:

In [126]:
# Resegnia nueva
res = 'The book of Don Quixote is a spectacular, beautiful and sublime work of Cervantes'

# Creamos la matriz dispersa con el vocabulario y los valores asociados
# ya almacenados de nuestro modelo, referente a la nueva resegnia
X = vect.transform([res])

# Creamos un dataframe para ver la matriz dispersa
reviews_transformed_new = pd.DataFrame(X.toarray(), columns=vect.get_feature_names())
reviews_transformed_new.head()
Out[126]:
10 able acting action actually ago amazing amazon author away ... work works world worst worth writing written wrong year years
0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.526808 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

1 rows × 200 columns

In [127]:
# Realizamos la prediccion del sentiminto
log_reg.predict(reviews_transformed_new)
Out[127]:
array([1], dtype=int64)

Por lo que se ha predicho que el sentimiento de la nueva reseña es positivo.