In [1]:
import gensim, logging, os
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
In [2]:
class Corpus(object):
'''Clase Corpus que permite leer de manera secuencial un directorio de documentos de texto'''
def __init__(self, directorio):
self.directory = directorio
def __iter__(self):
for fichero in os.listdir(self.directory):
for linea in open(os.path.join(self.directory, fichero)):
yield linea.split()
CORPUSDIR
contiene una colección de noticias en español (normalizada previamente a minúsculas y sin signos de puntuación) con alrededor de 150 millones de palabras. Entrenamos un modelo en un solo paso, ignorando aquellos tokens que aparecen menos de 10 veces, para descartar erratas.
In [3]:
CORPUSDIR = '/opt/textos/efe/txt/'
oraciones = Corpus(CORPUSDIR)
#model = gensim.models.Word2Vec(oraciones, min_count=10, size=150, workers=2)
# el modelo puede entrenarse en dos pasos sucesivos pero por separado
#model = gensim.models.Word2Vec() # modelo vacío
#model.build_vocab(oraciones) # primera pasada para crear la lista de vocabulario
#model.train(other_sentences) # segunda pasada para calcula vectores
Una vez completado el entrenamiento (después de casi 30 minutos), guardamos el modelo en disco.
In [ ]:
#model.save('/opt/textos/efe/efe.model.w2v')
En el futuro, podremos utilizar este modelo cargándolo en memoria con la instrucción:
In [4]:
model = gensim.models.Word2Vec.load('/opt/textos/efe/efe.model.w2v')
El objeto model
contiene una enorme matriz de números: una tabla, donde cada fila es uno de los términos del vocabulario reconocido y cada columna es una de las características que permiten modelar el significado de dicho término.
En nuestro modelo, tal y como está entrenado, tenemos más de 26 millones de términos:
In [5]:
print(model.corpus_count)
Cada término del vocabulario está representado como un vector con 150 dimensiones: 105 características. Podemos acceder al vector de un término concreto:
In [6]:
print(model['azul'], '\n')
print(model['verde'], '\n')
print(model['microsoft'])
Estos vectores no nos dicen mucho, salvo que contienen números muy pequeños :-/
El mismo objeto model
permite acceder a una serie de funcionalidades ya implementadas que nos van a permitir evaluar formal e informalmente el modelo. Por el momento, nos contentamos con los segundo: vamos a revisar visualmente los significados que nuestro modelo ha aprendido por su cuenta.
Podemos calcular la similitud semántica entre dos términos usando el método similarity
, que nos devuelve un número entre 0 y 1:
In [7]:
print('hombre - mujer', model.similarity('hombre', 'mujer'))
print('madrid - parís', model.similarity('madrid', 'parís'))
print('perro - gato', model.similarity('perro', 'gato'))
print('gato - periódico', model.similarity('gato', 'periódico'))
Podemos seleccionar el término que no encaja a partir de una determinada lista de términos usando el método doesnt_match
:
In [8]:
lista1 = 'madrid barcelona gonzález washington'.split()
print('en la lista', ' '.join(lista1), 'sobra:', model.doesnt_match(lista1))
lista2 = 'psoe pp ciu epi'.split()
print('en la lista', ' '.join(lista2), 'sobra:', model.doesnt_match(lista2))
lista3 = 'publicaron declararon soy negaron'.split()
print('en la lista', ' '.join(lista3), 'sobra:', model.doesnt_match(lista3))
lista3 = 'homero saturno cervantes shakespeare cela'.split()
print('en la lista', ' '.join(lista3), 'sobra:', model.doesnt_match(lista3))
Podemos buscar los términos más similares usando el método most_similar
de nuestro modelo:
In [9]:
terminos = 'psoe chicago sevilla aznar podemos estuvieron'.split()
for t in terminos:
print(t, '==>', model.most_similar(t), '\n')
Con el mismo método most_similar
podemos combinar vectores de palabras tratando de jugar con los rasgos semánticos de cada una de ellas para descubrir nuevas relaciones.
In [10]:
print('==> alcalde + mujer - hombre')
most_similar = model.most_similar(positive=['alcalde', 'mujer'], negative=['hombre'], topn=3)
for item in most_similar:
print(item)
print('==> madrid + filipinas - españa')
most_similar = model.most_similar(positive=['madrid', 'filipinas'], negative=['españa'], topn=3)
for item in most_similar:
print(item)
print('==> michel + fútbol + argentina - españa')
most_similar = model.most_similar(positive=['michel', 'fútbol', 'argentina'], negative=['españa'], topn=3)
for item in most_similar:
print(item)