import gensim, logging, os
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

"""
Explanation: Ejemplo de word2vec con gensim
En la siguiente celda, importamos las librerías necesarias y configuramos los mensajes de los logs.
End of explanation
"""


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()


"""
Explanation: Entrenamiento de un modelo
Implemento una clase Corpus con un iterador sobre un directorio que contiene ficheros de texto. Utilizaré una instancia de Corpus para poder procesar de manera más eficiente una colección, sin necesidad de cargarlo previamente en memoria.
End of explanation
"""


CORPUSDIR = 'PATH_TO_YOUR_CORPUS_DIRECTORY'
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

"""
Explanation: 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.
End of explanation
"""


model.save('PATH_TO_YOUR_MODEL.w2v')

"""
Explanation: Una vez completado el entrenamiento (después de casi 30 minutos), guardamos el modelo en disco.
End of explanation
"""


#model = gensim.models.Word2Vec.load('PATH_TO_YOUR_MODEL.w2v')
#model = gensim.models.Word2Vec.load('/data/w2v/eswiki-280.w2v')
model = gensim.models.Word2Vec.load('/data/w2v/efe.model.w2v')


"""
Explanation: En el futuro, podremos utilizar este modelo cargándolo en memoria con la instrucción:
End of explanation
"""


print(model.corpus_count)

"""
Explanation: Probando nuestro modelo
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:
End of explanation
"""


print(model['azul'], '\n')

print(model['verde'], '\n')

print(model['microsoft'])

"""
Explanation: 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:
End of explanation
"""


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'))

"""
Explanation: 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:
End of explanation
"""


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))

"""
Explanation: Podemos seleccionar el término que no encaja a partir de una determinada lista de términos usando el método doesnt_match:
End of explanation
"""


terminos = 'psoe chicago sevilla aznar podemos estuvieron'.split()
terminos = 'microsoft ibm iberia repsol'.split()

for t in terminos:
    print(t, '==>', model.most_similar(t), '\n')

"""
Explanation: Podemos buscar los términos más similares usando el método most_similar de nuestro modelo:
End of explanation
"""


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)

    
    

"""
Explanation: 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.
End of explanation
"""


