El siguiente ejemplo utiliza un dataset de productos de supermercado, y crear un clasificador para predecir la categoría del producto usando el nombre.
El dataset proviene de un web-scraping realizado en una página de un supermercado, y tiene la siguiente estructura:
Para lograr esto se utiliza el algoritmo de word2vec para transformar el texto en una matriz que represente los features o variables. En este ejemplo no se explica la teoría de word2vec, luego haré otro post sobre eso.
El proceso sigue estos pasos:
PASO 1: Entrenar Word2vec
Se entrena un modelo usando Word2vec, y se genera un diccionario (word vector) que tiene un vector numérico por cada palabra. Conceptualmente sería así:
PASO 2: Generar Features
Al entrenar Word2vec tenemos un vocabulario (word vector) donde cada palabra tiene un vector de igual tamaño. Ahora es necesario construir un vector único para cada producto, y para esto puede usarse el promedio de los vectores de cada palabra, que puede representarse así:
PASO 3: Entrenar un Clasificador
Cuando se genera el promedio de todos los vectores, se logra un dataset donde cada nombre de producto es definido por un vector que es el promedio de todas sus palabras, y entonces es posible entrenar un clasificador.
Conceptualmente sería así:
Al entrenar el modelo y realizar las predicciones en el conjunto de test, tenemos los siguientes resultados:
Script en Python con todos los pasos:
Ejemplo realizado con la version 3.8.3 de la libreria gensim
(pip install gensim==3.8.3)
import random as rd import pandas as pd import numpy as np from nltk.tokenize import RegexpTokenizer from nltk.corpus import stopwords from sklearn.model_selection import train_test_split as tts from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report from gensim.models.word2vec import Word2Vec class Word2VecClassification: def __init__(self, vector_size=10, window_size=3): self.vector_size = vector_size self.window_size = window_size self.tkr = RegexpTokenizer('[a-zA-Z]+') self.sw = stopwords.words('spanish') self.algorithm = RandomForestClassifier() self.model_w2v = None self.model_cls = None def buildWordVector(self, doc): vec_matrix = np.zeros(shape=(self.vector_size, len(doc))) for idw, word in enumerate(doc): if word not in self.sw: try: vec_matrix[:, idw] = self.model_w2v[word] except KeyError: continue return np.mean(vec_matrix, axis=1) def get_feature_from_vec(self, tokenized_corpus): print('getting feature from vectores...') docs = [] for doc in tokenized_corpus: doc = [x for x in doc if x not in self.sw] vec = self.buildWordVector(doc) vec = np.nan_to_num(vec.astype(np.float32)) docs.append(vec) return docs def get_tokenized_corpus(self, corpus): return [self.tkr.tokenize(text.strip().lower()) for text in corpus] def fit_w2v(self, tokenized_corpus): print('fitting word2vec...') return Word2Vec(sentences=tokenized_corpus, size=self.vector_size, window=self.window_size, min_count=2, negative=20, hs=0, ns_exponent=.5, cbow_mean=1, iter=150, sg=0, ) def fit(self, corpus, y_train): # train w2ec tokenized_corpus = self.get_tokenized_corpus(corpus) self.model_w2v = self.fit_w2v(tokenized_corpus) # train classification x_train = self.get_feature_from_vec(tokenized_corpus) self.model_cls = self.algorithm.fit(x_train, y_train) def predict(self, corpus): tokenized_corpus = self.get_tokenized_corpus(corpus) x = self.get_feature_from_vec(tokenized_corpus) return self.model_cls.predict(x) if __name__ == '__main__': # data target = 'category' corpus = 'product_name' url = 'https://www.dropbox.com/s/1n6tcxqptjysvvf/supermercado.csv?dl=1' data = pd.read_csv(url, encoding='utf-8') train, test = tts(data, train_size = 0.85) # train model = Word2VecClassification(vector_size=10, window_size=3) model.fit(train[corpus], train[target]) # predict predictions = model.predict(test[corpus]) report = classification_report(test[target], predictions) print(report)
Referencias:
El link con imágenes se puede descargar aqui
Que tal! Excelente explicación, solo me quedo la duda sobre los valores negativos que se obtuvieron en los vectores del paso 1, así como los valores negativos obtenidos en la paso 2, como se adquirieron esos datos? esos valores creo que están relacionados con el indice de similitud pero desconozco porque salen negativos. Espero y me puedas resolver esa duda
ResponderEliminarNuevamente muchas gracias por la explicación y el ejemplo
Saludos
Hola Edgar. Me alegra que te sirva esta publicaciòn. Sobre los valores negativos, te dejo este link con algunos detalles, espero te sirva: https://www.quora.com/What-should-I-do-if-I-got-negative-values-for-vectors
EliminarSuerte!