Apache spark Spark中HashingTF和CountVectorizer的区别是什么?

Apache spark Spark中HashingTF和CountVectorizer的区别是什么?,apache-spark,apache-spark-mllib,apache-spark-ml,Apache Spark,Apache Spark Mllib,Apache Spark Ml,尝试在Spark中进行文档分类。我不确定哈希在HashingTF中做了什么;它会牺牲准确性吗?我怀疑,但我不知道。spark doc说它使用了“散列技巧”。。。这只是工程师使用的另一个非常糟糕/混乱的命名示例(我也有罪)。CountVectorizer还需要设置词汇表大小,但它有另一个参数,阈值参数,可用于排除文本语料库中低于某个阈值的单词或标记。我不明白这两个变压器之间的区别。这一点的重要性在于算法中的后续步骤。例如,如果我想对生成的tfidf矩阵执行SVD,那么词汇表大小将决定SVD矩阵的大

尝试在Spark中进行文档分类。我不确定哈希在HashingTF中做了什么;它会牺牲准确性吗?我怀疑,但我不知道。spark doc说它使用了“散列技巧”。。。这只是工程师使用的另一个非常糟糕/混乱的命名示例(我也有罪)。CountVectorizer还需要设置词汇表大小,但它有另一个参数,阈值参数,可用于排除文本语料库中低于某个阈值的单词或标记。我不明白这两个变压器之间的区别。这一点的重要性在于算法中的后续步骤。例如,如果我想对生成的tfidf矩阵执行SVD,那么词汇表大小将决定SVD矩阵的大小,这会影响代码的运行时间,还有模型性能等。除了API文档和没有深度的非常琐碎的示例之外,我通常很难找到有关Spark Mllib的任何源代码。

散列技巧实际上是功能散列的另一个名称

我引用了维基百科的定义:

在机器学习中,与内核技巧类似,特征哈希(也称为哈希技巧)是一种快速且节省空间的特征矢量化方法,即将任意特征转化为向量或矩阵中的索引。它的工作原理是将哈希函数应用于特征,并将其哈希值直接用作索引,而不是在关联数组中查找索引

您可以在中阅读更多关于它的信息

实际上,对于节省空间的特征矢量化


然而,
CountVectorizer
只执行词汇提取,并将其转换为向量

几个重要的区别:

  • 部分可逆(
    countvectorier
    与不可逆(
    HashingTF
    )-由于哈希是不可逆的,因此无法从哈希向量恢复原始输入。从另一方面来说,带有模型(索引)的计数向量可用于恢复无序输入。因此,使用散列输入创建的模型可能更难解释和监控
  • 内存和计算开销-
    哈希函数
    只需要一次数据扫描,除了原始输入和向量之外,不需要额外的内存
    CountVectorizer
    需要对数据进行额外扫描以构建模型,并需要额外内存来存储词汇表(索引)。对于unigram语言模型,这通常不是一个问题,但对于较高的n-gram,这可能会非常昂贵或不可行
  • 哈希取决于向量的大小、哈希函数和文档。计数取决于向量的大小、训练语料库和文档
  • 信息丢失的一个来源-在
    HashingTF
    的情况下,这是可能发生冲突的降维<代码>计数向量器丢弃不常用的令牌。它如何影响下游模型取决于特定的用例和数据

根据Spark 2.1.0文档

HashingTF和CountVectorizer都可以用来生成术语频率向量

HashingTF

HashingTF是一个转换器,它接受术语集并进行转换 将这些集合转换为固定长度的特征向量。在文本处理中,一种 “术语集”可能是一堆单词HashingTF使用哈希技巧。原始特征通过应用散列映射到索引(术语) 功能。这里使用的散列函数是散列3。然后期限 根据映射的索引计算频率。这种方法 避免了计算索引映射的全局项的需要,可以 对于大型语料库来说代价很高,但它会受到潜在散列的影响 碰撞,其中不同的原始特征可能成为同一术语 散列后。

为了减少碰撞的机会,我们可以增加 目标特征维度,即散列的桶数 桌子因为一个简单的模用于将哈希函数转换为 对于列索引,建议使用二的幂作为特性 标注,否则要素将不会均匀映射到 柱。默认特征尺寸为2^18=262144。一 可选的二进制切换参数控制术语频率计数。什么时候 设置为真所有非零频率计数设置为1。这是 特别适用于对二进制数据建模的离散概率模型, 而不是整数

计数向量器

CountVectorizer和CountVectorizerModel旨在帮助转换 将文本文档集合到令牌计数向量。当 先验词典不可用,CountVectorizer可用作 提取词汇表的估计器,并生成 CountVectorizerModel。该模型为对象生成稀疏表示 通过词汇表创建文档,然后可以将这些文档传递给其他用户 像LDA这样的算法

在拟合过程中,CountVectorizer将选择顶部 词汇在语料库中按词汇频率排序。一 可选参数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函数。 与vocab大小无关,CountVectorizer函数估计术语频率,而无需任何近似值
 CountVectorizer(inputCol="words", outputCol="features")
      .fit(original_df)
      .transform(original_df)
 HashingTF(inputCol="words", outputCol="features")
      .transform(original_df)
// alternatively, define CountVectorizerModel with a-priori vocabulary
val cvm = new CountVectorizerModel(Array("a", "b", "c"))
  .setInputCol("words")
  .setOutputCol("features")

cvModel.transform(df).show(false)
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...
....v-------8x-------v....
...[0,1,2,6,8,11,12,13]...
...---------------v
... [1.0,1.0,1.0,3.0,1.0,1.0,1.0,1.0] ...