Sparkでドキュメント分類をしようとしています。 HashingTFでハッシュが何を行うかはわかりません。精度を犠牲にしますか?私はそれを疑いますが、知りません。 spark docは、「ハッシュトリック」を使用していると言います...エンジニアが使用する本当に悪い/混乱するネーミングのもう1つの例です(私も有罪です)。CountVectorizerには語彙の設定も必要ですサイズですが、別のパラメーターがあります。テキストコーパスの特定のしきい値より下に表示される単語またはトークンを除外するために使用できるしきい値パラメーターです。これらの2つのトランスフォーマーの違いがわかりません。これが重要なのは、アルゴリズム。たとえば、結果のtfidf行列でSVDを実行したい場合、語彙のサイズによってSVDの行列のサイズが決まり、コードの実行時間やモデルのパフォーマンスなどに影響を与えます。 Spark Mllibについての一般的なソースをAPIドキュメントを超えて見つけるのは困難であり、深さのない非常に簡単な例です。
いくつかの重要な違い:
CountVectorizer
)vs irreversible(HashingTF
)-ハッシュは元に戻せないため、ハッシュベクトルから元の入力を復元することはできません。一方、モデル(インデックス)を持つカウントベクトルは、順序付けられていない入力を復元するために使用できます。結果として、ハッシュされた入力を使用して作成されたモデルは、解釈および監視がはるかに困難になる可能性があります。HashingTF
は、単一のデータスキャンのみを必要とし、元の入力とベクトル以外に追加のメモリは必要ありません。 CountVectorizer
では、モデルを構築するためにデータをさらにスキャンし、語彙(インデックス)を保存するために追加のメモリが必要です。ユニグラム言語モデルの場合、それは通常問題ではありませんが、より高いNグラムの場合、それは法外に高価であるか、または実行不可能である可能性があります。HashingTF
の場合、衝突の可能性がある次元削減です。 CountVectorizer
は、頻度の低いトークンを破棄します。ダウンストリームモデルにどのように影響するかは、特定のユースケースとデータによって異なります。Spark 2.1.0ドキュメントに従って、
HashingTFとCountVectorizerの両方を使用して、用語周波数ベクトルを生成できます。
HashingTF
HashingTFは、用語のセットを取り、それらのセットを固定長の特徴ベクトルに変換するトランスフォーマーです。テキスト処理では、「用語のセット」は単語のバッグかもしれません。 HashingTFはハッシュトリックを利用しています。ハッシュ関数を適用することにより、生の特徴がインデックス(用語)にマップされます。ここで使用されるハッシュ関数はMurmurHash 3です。次に、マップされたインデックスに基づいて項頻度が計算されます。このアプローチでは、大規模なコーパスではコストが高くなる可能性があるグローバルな用語からインデックスへのマップを計算する必要がなくなりますが、ハッシュの衝突の可能性があり、ハッシュ後に異なる生の特徴が同じ用語になる可能性があります
衝突の可能性を減らすために、ターゲットフィーチャーの次元、つまりハッシュテーブルのバケットの数を増やすことができます。単純なモジュロを使用してハッシュ関数を列インデックスに変換するため、特徴の次元として2の累乗を使用することをお勧めします。そうしないと、特徴が列に均等にマッピングされません。デフォルトのフィーチャー寸法は2 ^ 18 = 262,144です。オプションのバイナリトグルパラメーターは、用語の頻度カウントを制御します。 trueに設定すると、ゼロ以外のすべての頻度カウントが1に設定されます。これは、整数ではなくバイナリカウントをモデル化する離散確率モデルで特に役立ちます。
CountVectorizer
CountVectorizerおよびCountVectorizerModelの目的は、テキストドキュメントのコレクションをトークンカウントのベクトルに変換することです。アプリオリ辞書が利用できない場合、CountVectorizerをEstimatorとして使用してvocabularyを抽出し、CountVectorizerModelを生成できます。モデルは、ドキュメントのスパース表現over the vocabularyを生成し、LDAなどの他のアルゴリズムに渡すことができます。
フィッティングプロセス中に、CountVectorizerは、コーパス全体の用語頻度で並べ替えられた上位のvocabSize単語を選択します。オプションのパラメーターminDFは、用語が語彙に含まれるために出現する必要があるドキュメントの最小数(または<1.0の場合は小数)を指定することによって、フィッティングプロセスにも影響を与えます。別のオプションのバイナリトグルパラメーターは、出力ベクトルを制御します。 trueに設定すると、ゼロ以外のすべてのカウントが1に設定されます。これは、整数ではなくバイナリのカウントをモデル化する離散確率モデルで特に役立ちます。
サンプルコード
from pyspark.ml.feature import HashingTF, IDF, Tokenizer
from pyspark.ml.feature import CountVectorizer
sentenceData = spark.createDataFrame([
(0.0, "Hi I heard about Spark"),
(0.0, "I wish Java could use case classes"),
(1.0, "Logistic regression models are neat")],
["label", "sentence"])
tokenizer = Tokenizer(inputCol="sentence", outputCol="words")
wordsData = tokenizer.transform(sentenceData)
hashingTF = HashingTF(inputCol="words", outputCol="Features", numFeatures=100)
hashingTF_model = hashingTF.transform(wordsData)
print "Out of hashingTF function"
hashingTF_model.select('words',col('Features').alias('Features(vocab_size,[index],[tf])')).show(truncate=False)
# fit a CountVectorizerModel from the corpus.
cv = CountVectorizer(inputCol="words", outputCol="Features", vocabSize=20)
cv_model = cv.fit(wordsData)
cv_result = model.transform(wordsData)
print "Out of CountVectorizer function"
cv_result.select('words',col('Features').alias('Features(vocab_size,[index],[tf])')).show(truncate=False)
print "Vocabulary from CountVectorizerModel is \n" + str(cv_model.vocabulary)
出力は以下のようになります
ハッシュTFは、LDAのようなテクニックに不可欠な語彙を逃しています。このためには、CountVectorizer関数を使用する必要があります。語彙サイズに関係なく、CountVectorizer関数は、HashingTFとは異なり、近似を行わずに用語の頻度を推定します。
参照:
https://spark.Apache.org/docs/latest/ml-features.html#tf-idf
https://spark.Apache.org/docs/latest/ml-features.html#countvectorizer
ハッシュトリックは、実際には機能ハッシュの別名です。
私はウィキペディアの定義を引用しています:
機械学習では、ハッシュトリックとも呼ばれる特徴ハッシュは、カーネルトリックに類似しており、特徴をベクトル化する高速でスペース効率の良い方法です。つまり、任意の特徴をベクトルまたは行列のインデックスに変換します。これは、連想配列でインデックスを調べるのではなく、ハッシュ関数を機能に適用し、ハッシュ値をインデックスとして直接使用することで機能します。
詳細は この論文 をご覧ください。
したがって、実際にはスペース効率の良い機能のベクトル化のために。
一方、CountVectorizer
は語彙抽出のみを実行し、ベクターに変換します。
答えは素晴らしいです。このAPIの違いを強調したいだけです。
CountVectorizer
はfit
でなければなりません。これにより、新しい CountVectorizerModel
が生成されます。これはtransform
になります。HashingTF
はfit
である必要はありません、HashingTF
インスタンスは直接変換できます例えば
_ CountVectorizer(inputCol="words", outputCol="features")
.fit(original_df)
.transform(original_df)
_
対:
_ HashingTF(inputCol="words", outputCol="features")
.transform(original_df)
_
このAPIの違いでは、CountVectorizer
には追加のfit
APIステップがあります。多分これは、CountVectorizer
が余分な作業を行うためです(受け入れられた回答を参照):
CountVectorizerは、モデルを構築するためにデータをさらにスキャンし、語彙(インデックス)を保存するために追加のメモリを必要とします。
例に示されている のようにCountVectorizerModel
を直接作成できる場合は、フィッティング手順をスキップすることもできると思います。
_// alternatively, define CountVectorizerModel with a-priori vocabulary
val cvm = new CountVectorizerModel(Array("a", "b", "c"))
.setInputCol("words")
.setOutputCol("features")
cvModel.transform(df).show(false)
_
別の大きな違い!
HashingTF
は衝突を引き起こす可能性があります!つまり、2つの異なる特徴/単語は同じ用語として扱われます。受け入れられた答えはこれを言います:
情報損失の原因-HashingTFの場合、衝突の可能性がある次元削減です
これは特に、明示的な低いnumFeatures
値(pow(2,4)
、pow(2,8)
)の問題です。デフォルト値はかなり高い(pow(2,20)
)この例では:
_wordsData = spark.createDataFrame([([
'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'ten'],)], ['tokens'])
hashing = HashingTF(inputCol="tokens", outputCol="hashedValues", numFeatures=pow(2,4))
hashed_df = hashing.transform(wordsData)
hashed_df.show(truncate=False)
+-----------------------------------------------------------+
|hashedValues |
+-----------------------------------------------------------+
|(16,[0,1,2,6,8,11,12,13],[1.0,1.0,1.0,3.0,1.0,1.0,1.0,1.0])|
+-----------------------------------------------------------+
_
出力には16個の「ハッシュバケット」が含まれています(私がnumFeatures=pow(2,4)
を使用したため)。
_...16...
_
私の入力には10個の一意のトークンがありましたが、出力には8個の一意のハッシュのみが作成されます(ハッシュの衝突のため);
_....v-------8x-------v....
...[0,1,2,6,8,11,12,13]...
_
ハッシュの衝突は、3つの異なるトークンに同じハッシュが与えられることを意味します(すべてのトークンは一意ですが、1回のみ発生するはずです)。
_...---------------v
... [1.0,1.0,1.0,3.0,1.0,1.0,1.0,1.0] ...
_
(したがって、デフォルト値のままにするか、衝突を回避するために numFeatures
を増やします :
この[ハッシュ]アプローチでは、大規模なコーパスではコストが高くなる可能性があるグローバルな用語からインデックスへのマップを計算する必要がなくなりますが、ハッシュの衝突の可能性があり、ハッシュ後に異なる生の特徴が同じ用語になる可能性があります。衝突の可能性を減らすために、ターゲットフィーチャーの次元、つまりハッシュテーブルのバケット数を増やすことができます。
その他のAPIの違い
CountVectorizer
コンストラクター(初期化時)は追加のパラメーターをサポートします:
minDF
minTF
CountVectorizerModel
にはvocabulary
メンバー があるため、生成されたvocabulary
を確認できます(fit
your CountVectorizer
):
countVectorizerModel.vocabulary
_>>> [u'one', u'two', ...]
_CountVectorizer
は、主な答えが言うように「リバーシブル」です!インデックスを用語にマップする配列であるそのvocabulary
メンバーを用語 ((sklearn
's CountVectorizer
は何か似ている) を使用します