2017-01-19 19 views
1

У меня есть этот код,Как правильно сделать TF-IDF-векторы предложений в Apache Spark с Java?

public class TfIdfExample { 
     public static void main(String[] args){ 
      JavaSparkContext sc = SparkSingleton.getContext(); 
      SparkSession spark = SparkSession.builder() 
        .config("spark.sql.warehouse.dir", "spark-warehouse") 
        .getOrCreate(); 
      JavaRDD<List<String>> documents = sc.parallelize(Arrays.asList(
        Arrays.asList("this is a sentence".split(" ")), 
        Arrays.asList("this is another sentence".split(" ")), 
        Arrays.asList("this is still a sentence".split(" "))), 2); 


      HashingTF hashingTF = new HashingTF(); 
      documents.cache(); 
      JavaRDD<Vector> featurizedData = hashingTF.transform(documents); 
      // alternatively, CountVectorizer can also be used to get term frequency vectors 

      IDF idf = new IDF(); 
      IDFModel idfModel = idf.fit(featurizedData); 

      featurizedData.cache(); 

      JavaRDD<Vector> tfidfs = idfModel.transform(featurizedData); 
      System.out.println(tfidfs.collect()); 
      KMeansProcessor kMeansProcessor = new KMeansProcessor(); 
      JavaPairRDD<Vector,Integer> result = kMeansProcessor.Process(tfidfs); 
      result.collect().forEach(System.out::println); 
     } 
    } 

мне нужно получить векторы для K-средних, но я получаю нечетные векторы

[(1048576,[489554,540177,736740,894973],[0.28768207245178085,0.0,0.0,0.0]), 
    (1048576,[455491,540177,736740,894973],[0.6931471805599453,0.0,0.0,0.0]), 
    (1048576,[489554,540177,560488,736740,894973],[0.28768207245178085,0.0,0.6931471805599453,0.0,0.0])] 

после к-средства работы я получаю это

((1048576,[489554,540177,736740,894973],[0.28768207245178085,0.0,0.0,0.0]),1) 
((1048576,[489554,540177,736740,894973],[0.28768207245178085,0.0,0.0,0.0]),0) 
((1048576,[489554,540177,736740,894973],[0.28768207245178085,0.0,0.0,0.0]),1) 
((1048576,[455491,540177,736740,894973],[0.6931471805599453,0.0,0.0,0.0]),1) 
((1048576,[489554,540177,560488,736740,894973],[0.28768207245178085,0.0,0.6931471805599453,0.0,0.0]),1) 
((1048576,[455491,540177,736740,894973],[0.6931471805599453,0.0,0.0,0.0]),0) 
((1048576,[455491,540177,736740,894973],[0.6931471805599453,0.0,0.0,0.0]),1) 
((1048576,[489554,540177,560488,736740,894973],[0.28768207245178085,0.0,0.6931471805599453,0.0,0.0]),0) 
((1048576,[489554,540177,560488,736740,894973],[0.28768207245178085,0.0,0.6931471805599453,0.0,0.0]),1) 

Но я думаю, что это работает неправильно, потому что tf-idf должен иметь другое представление. Я думаю, что у mllib есть готовые методы для этого, но я протестировал примеры документации и не получил то, что мне нужно. Специального решения для Spark я не нашел. Может кто-нибудь работать с ним и дать мне ответ, что я делаю неправильно? Может быть, я неправильно использую функциональность mllib?

ответ

1

Что вы получаете после TF-IDF - это SparseVector.

Чтобы понять значение лучше, позвольте мне начать с векторами TF:

(1048576,[489554,540177,736740,894973],[1.0,1.0,1.0,1.0]) 
(1048576,[455491,540177,736740,894973],[1.0,1.0,1.0,1.0]) 
(1048576,[489554,540177,560488,736740,894973],[1.0,1.0,1.0,1.0,1.0]) 

Например, вектор TF, соответствующий первое предложением является вектор а 1048576 (= 2^20) компонента, с 4 ненулевыми значениями, соответствующими к индексам 489554,540177,736740 и 894973 все остальные значения являются нулями и поэтому не сохраняются в разреженном векторном представлении.

Размерность векторов признаков равна числу ведер, которые вы вставляете в: 1048576 = 2^20 ведра в вашем случае.

Для корпуса этого размера, вы должны рассмотреть вопрос о сокращении количества ковшей:

HashingTF hashingTF = new HashingTF(32); 

силы 2 рекомендуется, чтобы минимизировать количество хэш столкновений.

Далее вы применяете IDF весов:

(1048576,[489554,540177,736740,894973],[0.28768207245178085,0.0,0.0,0.0]) 
(1048576,[455491,540177,736740,894973],[0.6931471805599453,0.0,0.0,0.0]) 
(1048576,[489554,540177,560488,736740,894973],[0.28768207245178085,0.0,0.6931471805599453,0.0,0.0]) 

Если мы еще раз посмотрим на первое предложение, мы получили 3 нули - которые, как ожидается, так как термины «это», «есть», и «предложение "появляются в каждом документе корпуса, поэтому by definition of IDF будет равен нулю.

Почему нулевые значения остаются в (редких) вектор? Потому что в текущей реализации the size of the vector is kept the same и только значения умножаются на IDF.

+0

Благодарим вас, но что означают, что я подразумеваю, что распечатка была усечена, я копирую все с консоли. И поскольку я думаю, что tf-idf не вернет мне никаких истинных векторов. Я делаю 'new HashingTF (32);' и идентификаторы в первом кортеже становятся меньше. Но я не понимаю, почему в некоторых значениях во втором корте я получаю 0.0 –

+1

Я запустил ваш пример, и действительно эти значения должны быть равны нулю. Я добавил дополнительные сведения/ссылки на объяснение - дайте мне знать, если это поможет. –

+0

Один вопрос: '(1048576, [489554,540177,736740,894973], [0.28768207245178085,0.0,0.0,0.0])' в этом векторе '[0.28768207245178085,0.0,0.0,0.0]' it tf-idf после применения IDF к TF? –