Рассчитать TF-IDF сгруппированы по столбцам - PullRequest
0 голосов
/ 30 мая 2018

Как я могу вычислить tf-idf, сгруппированный по столбцу, а не по всему фрейму данных?

Предположим, что в фрейме данных, как показано ниже

private val sample = Seq(
    (1, "A B C D E"),
    (1, "B C D"),
    (1, "B C D E"),
    (2, "B C D F"),
    (2, "A B C"),
    (2, "B C E F G")
  ).toDF("id","sentences")

В приведенном выше примере IDF должен быть рассчитан для предложенийс id = 1 с учетом первых трех элементов.Аналогичным образом IDF должен рассчитываться для предложений с Id = 2 с учетом последних трех элементов.Возможно ли это в реализации spf ml's tf-idf.

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Вы можете сгруппировать фрейм данных по id и сгладить соответствующие токенизированные слова перед вычислением TF-IDF.Ниже приведен фрагмент кода примера Spark TF-IDF doc:

val sample = Seq(
  (1, "A B C D E"),
  (1, "B C D"),
  (1, "B C D E"),
  (2, "B C D F"),
  (2, "A B C"),
  (2, "B C E F G")
).toDF("id","sentences")

import org.apache.spark.sql.functions._
import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer}

val tokenizer = new Tokenizer().setInputCol("sentences").setOutputCol("words")
val wordsDF = tokenizer.transform(sample)

def flattenWords = udf( (s: Seq[Seq[String]]) => s.flatMap(identity) )

val groupedDF = wordsDF.groupBy("id").
  agg(flattenWords(collect_list("words")).as("grouped_words"))

val hashingTF = new HashingTF().
  setInputCol("grouped_words").setOutputCol("rawFeatures").setNumFeatures(20)
val featurizedData = hashingTF.transform(groupedDF)
val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
val idfModel = idf.fit(featurizedData)
val rescaledData = idfModel.transform(featurizedData)

rescaledData.show
// +---+--------------------+--------------------+--------------------+
// | id|       grouped_words|         rawFeatures|            features|
// +---+--------------------+--------------------+--------------------+
// |  1|[a, b, c, d, e, b...|(20,[1,2,10,14,18...|(20,[1,2,10,14,18...|
// |  2|[b, c, d, f, a, b...|(20,[1,2,8,10,14,...|(20,[1,2,8,10,14,...|
// +---+--------------------+--------------------+--------------------+
0 голосов
/ 30 мая 2018

Просто неудачная попытка: вы можете отфильтровать свою последовательность по идентификатору и преобразовать каждый фильтр в информационный фрейм и сохранить их в списке, а затем использовать цикл для применения вашего tf-idf к каждому фрейму данных в вашем списке.

var filters=List[org.apache.spark.sql.DataFrame]()
val mySeq=Seq((1, "A B C D E"),(1, "B C D"),(1, "B C D E"),(2, "B C D F"),(2, "A B C"),(2, "B C E F G")) 
for(i<-List(1,2)){filters=filters:+s.filter{case x=>x._1==i}.toDF("id","sentences")}   

Так, например, у вас есть

scala> filters(0).show()
+---+---------+
| id|sentences|
+---+---------+
|  1|A B C D E|
|  1|    B C D|
|  1|  B C D E|
+---+---------+

scala> filters(1).show()
+---+---------+
| id|sentences|
+---+---------+
|  2|  B C D F|
|  2|    A B C|
|  2|B C E F G|
+---+---------+

, и вы можете выполнять вычисления TF-IDF для каждого кадра данных, используя цикл или map.

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

...