Estoy usando la biblioteca gensim de Python para hacer una indexación semántica latente. Seguí los tutoriales en el sitio web, y funciona bastante bien. Ahora estoy tratando de modificarlo un poco; Quiero ejecutar el modelo lsi cada vez que se agrega un documento.

Aquí está mi código:

stoplist = set('for a of the and to in'.split())
num_factors=3
corpus = []

for i in range(len(urls)):
 print "Importing", urls[i]
 doc = getwords(urls[i])
 cleandoc = [word for word in doc.lower().split() if word not in stoplist]
 if i == 0:
  dictionary = corpora.Dictionary([cleandoc])
 else:
  dictionary.addDocuments([cleandoc])
 newVec = dictionary.doc2bow(cleandoc)
 corpus.append(newVec)
 tfidf = models.TfidfModel(corpus)
 corpus_tfidf = tfidf[corpus]
 lsi = models.LsiModel(corpus_tfidf, numTopics=num_factors, id2word=dictionary)
 corpus_lsi = lsi[corpus_tfidf]

Geturls es una función que escribí que devuelve el contenido de un sitio web como una cadena. Nuevamente, funciona si espero hasta que procese todos los documentos antes de hacer tfidf y lsi, pero eso no es lo que quiero. Quiero hacerlo en cada iteración. Lamentablemente, recibo este error:

    Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "streamlsa.py", line 51, in <module>
    lsi = models.LsiModel(corpus_tfidf, numTopics=num_factors, id2word=dictionary)
  File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 303, in __init__
    self.addDocuments(corpus)
  File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 365, in addDocuments
    self.printTopics(5) # TODO see if printDebug works and remove one of these..
  File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 441, in printTopics
    self.printTopic(i, topN = numWords)))
  File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/models/lsimodel.py", line 433, in printTopic
    return ' + '.join(['%.3f*"%s"' % (1.0 * c[val] / norm, self.id2word[val]) for val in most])
  File "/Library/Python/2.6/site-packages/gensim-0.7.8-py2.6.egg/gensim/corpora/dictionary.py", line 52, in __getitem__
    return self.id2token[tokenid] # will throw for non-existent ids
KeyError: 1248

Por lo general, el error aparece en el segundo documento. Creo que entiendo lo que me está diciendo (los índices del diccionario son malos), simplemente no puedo entender por qué. He intentado muchas cosas diferentes y nada parece funcionar. ¿Alguien sabe lo que está pasando?

¡Gracias!

4
Jeff 9 jun. 2011 a las 06:20

3 respuestas

La mejor respuesta

Esto fue un error en gensim, donde el mapeo inverso id-> word se almacena en caché, pero el caché no se actualizó después de addDocuments().

Se arregló en este commit en 2011: https://github.com/piskvorky/gensim/commit/ b88225cfda8570557d3c72b0820fefb48064a049.

4
Radim 25 abr. 2014 a las 08:44

Bien, entonces encontré una solución, aunque no una óptima.

Si crea un diccionario con corpora.Dictionary y luego agrega documentos inmediatamente con dictionary.addDocuments, todo funciona bien.

Pero, si usa el diccionario entre estas dos llamadas (llamando dictionary.doc2bow o adjuntando su diccionario a un modelo lsi con id2word), entonces su diccionario está 'congelado' y no se puede actualizar Puede llamar a dictionary.addDocuments y le le dirá que está actualizado, e incluso le dirá qué tan grande es el nuevo diccionario, por ejemplo:

INFO:dictionary:built Dictionary(6627 unique tokens) from 8 documents (total 24054 corpus positions)

Pero cuando hace referencia a cualquiera de los nuevos índices, obtiene un error. No estoy seguro de si esto es un error o si esto fue intencionado (por alguna razón), pero al menos el hecho de que gensim informes agrega con éxito el documento al diccionario es seguramente un error.

Primero intenté poner las llamadas del diccionario en funciones separadas, donde solo se debería modificar la copia local del diccionario. Bueno, todavía se rompe. Esto es extraño para mí, y no tengo idea de por qué.

El siguiente paso fue intentar pasar una copia del diccionario, usando copy.copy. Esto funciona, pero obviamente usará un poco más de gastos generales. Sin embargo, le permitirá mantener una copia de trabajo de su corpus y diccionario. Sin embargo, el mayor inconveniente aquí, para mí, fue que esta solución no me permite eliminar palabras que aparecieron solo una vez en el corpus usando filterTokens, porque eso implicaría modificar el diccionario.

Mi otra solución es simplemente reconstruir todo (el corpus, el diccionario, los modelos lsi y tfidf) en cada iteración. Con mi pequeño conjunto de datos de muestra, esto me da resultados ligeramente mejores, pero no es escalable a conjuntos de datos muy grandes sin incurrir en problemas de memoria. Aún así, por ahora esto es lo que estoy haciendo.

Si algún usuario experimentado de gensim tiene una solución mejor (y más amigable con la memoria) para que no tenga problemas con conjuntos de datos más grandes, ¡hágamelo saber!

1
Jeff 9 jun. 2011 a las 06:17

En doc2bow, puede establecer allow_update = True y actualizará automáticamente su diccionario con cada iteración de doc2bow

http://radimrehurek.com/gensim/corpora/dictionary.html

0
dmil 12 ago. 2013 a las 18:42