Извлечь матрицу документа-темы из модели Pyspark LDA

Я успешно подготовил модель LDA в иске, используя API Python:

from pyspark.mllib.clustering import LDA
model=LDA.train(corpus,k=10)

Это работает отлично, но теперь мне нужна матрица документа-темы для модели LDA, но насколько я могу сказать, все, что я могу получить, это слово-тема, используя model.topicsMatrix().

Есть ли способ получить матрицу типа документа из модели LDA, а если нет, есть ли альтернативный метод (кроме реализации LDA с нуля) в Spark для запуска модели LDA, которая даст мне результат я нужно?

EDIT:

После небольшого поиска я нашел документацию для DistributedLDAModel в Java api, у которой есть topicDistributions(), который, я думаю, является именно тем, что мне нужно здесь (но я на 100% уверен, что LDAModel в Pyspark на самом деле является DistributedLDAModel под капотом...).

В любом случае, я могу косвенно вызвать этот метод так, без каких-либо явных сбоев:

In [127]: model.call('topicDistributions')
Out[127]: MapPartitionsRDD[3156] at mapPartitions at PythonMLLibAPI.scala:1480

Но если я действительно посмотрю на результаты, все, что я получаю, это строка, которая говорит мне, что результат на самом деле является корнем Scala (я думаю):

In [128]: model.call('topicDistributions').take(5)
Out[128]:
[{u'__class__': u'scala.Tuple2'},
 {u'__class__': u'scala.Tuple2'},
 {u'__class__': u'scala.Tuple2'},
 {u'__class__': u'scala.Tuple2'},
 {u'__class__': u'scala.Tuple2'}]

Возможно, это, как правило, правильный подход, но есть ли способ получить фактические результаты?

Ответ 1

После обширных исследований это невозможно сделать с помощью Python api в текущей версии Spark (1.5.1). Но в Scala он довольно прост (с учетом RDD documents, на котором нужно тренироваться):

import org.apache.spark.mllib.clustering.{LDA, DistributedLDAModel}

// first generate RDD of documents...

val numTopics = 10
val lda = new LDA().setK(numTopics).setMaxIterations(10)
val ldaModel = lda.run(documents)

# then convert to distributed LDA model
val distLDAModel = ldaModel.asInstanceOf[DistributedLDAModel]

Затем получение распределений разделов документа так же просто, как:

distLDAModel.topicDistributions

Ответ 2

Ниже приведен пример ответа для PySpark и Spark 2.0.

Надеюсь, вы извините меня за публикацию этого ответа вместо комментария, но в данный момент мне не хватает репутации.

Я предполагаю, что у вас есть подготовленная модель LDA, сделанная из корпуса, например:

lda = LDA(k=NUM_TOPICS, optimizer="em")
ldaModel = lda.fit(corpus) # Where corpus is a dataframe with 'features'.

Чтобы преобразовать документ в дистрибутив темы, мы создаем dataframe идентификатора документа и вектор (более редкий) слов.

documents = spark.createDataFrame([
    [123myNumericId, Vectors.sparse(len(words_in_our_corpus), {index_of_word:count}],
    [2, Vectors.sparse(len(words_in_our_corpus), {index_of_word:count, another:1.0}],
], schema=["id", "features"]
transformed = ldaModel.transform(documents)
dist = transformed.take(1)
# dist[0]['topicDistribution'] is now a dense vector of our topics.

Ответ 3

С Spark 2.0 вы можете использовать transform() как метод из pyspark.ml.clustering.DistributedLDAModel. Я просто попробовал это на 20 наборе информационных групп из scikit-learn, и это работает. См. Возвращенный vectors, который является распределением по темам для документа.

>>> test_results = ldaModel.transform(wordVecs)
Row(filename='/home/jovyan/work/data/20news_home/20news-bydate-test/rec.autos/103343', target=7, text='I am a little confused on all of the models of the 88-89 bonnevilles.\nI have heard of the LE SE LSE SSE SSEI. Could someone tell me the\ndifferences are far as features or performance. I am also curious to\nknow what the book value is for prefereably the 89 model. And how much\nless than book value can you usually get them for. In other words how\nmuch are they in demand this time of year. I have heard that the mid-spring\nearly summer is the best time to buy.', tokens=['little', 'confused', 'models', 'bonnevilles', 'someone', 'differences', 'features', 'performance', 'curious', 'prefereably', 'usually', 'demand', 'spring', 'summer'], vectors=SparseVector(10977, {28: 1.0, 29: 1.0, 152: 1.0, 301: 1.0, 496: 1.0, 552: 1.0, 571: 1.0, 839: 1.0, 1114: 1.0, 1281: 1.0, 1288: 1.0, 1624: 1.0}), topicDistribution=DenseVector([0.0462, 0.0538, 0.045, 0.0473, 0.0545, 0.0487, 0.0529, 0.0535, 0.0467, 0.0549, 0.051, 0.0466, 0.045, 0.0487, 0.0482, 0.0509, 0.054, 0.0472, 0.0547, 0.0501]))