3

Я новый Спарк 2. я попытался Спарк tfidf напримерКак Спарк HashingTF работает

sentenceData = spark.createDataFrame([ 
    (0.0, "Hi I heard about Spark") 
], ["label", "sentence"]) 

tokenizer = Tokenizer(inputCol="sentence", outputCol="words") 
wordsData = tokenizer.transform(sentenceData) 


hashingTF = HashingTF(inputCol="words", outputCol="rawFeatures", numFeatures=32) 
featurizedData = hashingTF.transform(wordsData) 

for each in featurizedData.collect(): 
    print(each) 

Он выводит

Row(label=0.0, sentence=u'Hi I heard about Spark', words=[u'hi', u'i', u'heard', u'about', u'spark'], rawFeatures=SparseVector(32, {1: 3.0, 13: 1.0, 24: 1.0})) 

Я ожидал, что в rawFeatures я буду получать долгосрочные частоты как {0:0.2, 1:0.2, 2:0.2, 3:0.2, 4:0.2}. Поскольку частота терминов является:

tf(w) = (Number of times the word appears in a document)/(Total number of words in the document) 

В нашем случае это: tf(w) = 1/5 = 0.2 для каждого слова, потому что каждое слово apears один раз в документе. Если мы представляем, что выходной словарь rawFeatures содержит индекс слова как ключ, а количество слов в документе как значение, то почему ключ 1 равен 3.0? Нет слова, которое появляется в документе 3 раза. Это меня смущает. Что мне не хватает?

ответ

2

TL; DR; Это просто хэш-столкновение. HashingTF принимает hash(word) % numBuckets, чтобы определить ведро и с очень низким количеством ковшей, как здесь следует ожидать столкновений. В общем, вы должны использовать гораздо большее количество ковшей или, если столкновения неприемлемы, CountVectorizer.

Подробнее. HashingTF по умолчанию использует хеш Murmur. [u'hi', u'i', u'heard', u'about', u'spark'] будет хэширован до [-537608040, -1265344671, 266149357, 146891777, 2101843105]. Если вы follow the source вы увидите, что реализация эквивалентна:

import org.apache.spark.unsafe.types.UTF8String 
import org.apache.spark.unsafe.hash.Murmur3_x86_32.hashUnsafeBytes 

Seq("hi", "i", "heard", "about", "spark") 
    .map(UTF8String.fromString(_)) 
    .map(utf8 => 
    hashUnsafeBytes(utf8.getBaseObject, utf8.getBaseOffset, utf8.numBytes, 42)) 
Seq[Int] = List(-537608040, -1265344671, 266149357, 146891777, 2101843105) 

Когда вы non-negative modulo этих значений вы получите [24, 1, 13, 1, 1]:

List(-537608040, -1265344671, 266149357, 146891777, 2101843105) 
    .map(nonNegativeMod(_, 32)) 
List[Int] = List(24, 1, 13, 1, 1) 

Три слова из хеш списка (i, about и spark) в одно и то же ведро, каждый из них происходит один раз, следовательно, результат получается.

Похожие: