尝试在Spark中进行文档分类。我不知道hashing在hashingTF中做了什么;它是否牺牲了准确性?我很怀疑,但我不知道。spark doc说它使用了“散列技巧”。。这只是工程师使用的另一个非常糟糕/令人困惑的命名的例子(我也很内疚)。CountVectorizer也需要设置词汇表大小,但它有另一个参数,一个阈值参数,可用于排除文本语料库中低于某个阈值的单词或标记。我不明白这两个变形金刚之间的区别。使这一点变得重要的是算法中的后续步骤。例如,如果我想对结果tfidf矩阵执行SVD,那么词汇表大小将决定SVD矩阵的大小,这会影响代码的运行时间和模型性能等。除了API文档和没有深度的琐碎示例之外,我很难找到任何关于Spark Mllib的来源。
4条答案
按热度按时间pxiryf3j1#
几个重要的区别:
CountVectorizer
)vs unreversible(HashingTF
)-由于哈希是不可逆的,因此无法从哈希向量恢复原始输入。从另一方面,具有模型(索引)的计数向量可以用于恢复无序输入。因此,使用散列输入创建的模型可能更难以解释和监视。*内存和计算开销-
HashingTF
只需要一次数据扫描,除了原始输入和向量之外,不需要额外的内存。CountVectorizer
需要对数据进行额外的扫描以构建模型,并需要额外的内存来存储词汇表(索引)。在unigram语言模型的情况下,这通常不是问题,但在更高的n-gram的情况下,它可能非常昂贵或不可行。*信息丢失的来源-在
HashingTF
的情况下,它是具有可能的冲突的维度缩减。CountVectorizer
丢弃不常用的令牌。它如何影响下游模型取决于特定的用例和数据。yyhrrdl82#
根据Spark 2.1.0文档,
HashingTF和CountVectorizer都可用于生成词频向量。
哈希TF
HashingTF是一个Transformer,它采用术语集并将这些集合转换为固定长度的特征向量。在文本处理中,“术语集”可能是一个词袋。**HashingTF使用哈希技巧。通过应用散列函数将原始特征Map到索引(项)。这里使用的哈希函数是MurmurHash 3。然后基于Map的索引计算词频。这种方法避免了计算全局术语到索引Map的需要,这对于大型语料库来说可能是昂贵的,但它遭受了潜在的哈希冲突,其中不同的原始特征在哈希之后可能变成相同的术语。
为了减少碰撞的机会,我们可以增加目标特征维度,即哈希表的桶数。由于使用简单的模来将散列函数转换为列索引,因此建议使用2的幂作为特征维度,否则特征将不会均匀地Map到列。默认特征尺寸为2^18= 262,144。可选的二进制切换参数控制词频计数。当设置为true时,所有非零频率计数均设置为1。这对于建模二进制而非整数计数的离散概率模型尤其有用。
计数向量器
*CountVectorizer和CountVectorizerModel旨在帮助将文本文档集合转换为令牌计数的向量。当先验字典不可用时,CountVectorizer可以用作Estimator以提取 * 词汇表 ,并生成CountVectorizer模型。该模型为文档 * 在词汇表 * 上生成稀疏表示,然后可以将其传递给其他算法,如LDA。
在拟合过程中,CountVectorizer将选择在语料库中按词频排序的最高vocabSize单词。一个可选参数minDF也会影响拟合过程,它指定词汇表中包含的术语必须出现的文档的最小数量(如果< 1.0,则为分数)。另一个可选的二进制切换参数控制输出向量。如果设置为真,则所有非零计数都设置为1。这对于建模二进制而非整数计数的离散概率模型尤其有用。
示例代码
输出如下
散列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
7lrncoxx3#
哈希技巧实际上是特征哈希的另一个名称。
我引用维基百科的定义:
在机器学习中,特征散列,也称为散列技巧,与内核技巧类似,是一种快速且空间高效的特征向量化方法,即将任意特征转换为向量或矩阵中的索引。它的工作原理是将散列函数应用于特征,并直接使用其散列值作为索引,而不是在关联数组中查找索引。
您可以在this paper中阅读更多信息。
所以实际上是为了空间有效的特征矢量化。
而
CountVectorizer
只执行词汇提取,并转换为Vectors。o4tp2gmn4#
答案很棒。我只想再提几点:
API差异:CountVectorizer必须匹配
CountVectorizer
必须是fit
,这会产生一个新的CountVectorizerModel
,它可以是transform
HashingTF
不需要是fit
,HashingTF
示例可以直接转换比如说,
对比:
在这个API中,
CountVectorizer
有一个额外的fit
API步骤。也许这是因为CountVectorizer
做了额外的工作来创建一个词汇表(参见接受的答案):CountVectorizer需要对数据进行额外扫描以构建模型,并需要额外内存来存储词汇表(索引)。
我认为如果你能够直接“使用先验词汇表”创建你的
CountVectorizerModel
,你也可以跳过拟合步骤,如示例所示:冲突差异:HashingTF碰撞势
HashingTF
可能会产生冲突!这意味着两个不同的特征/词被视为 * 相同的术语 。接受的答案是这样的:......信息丢失的来源-在HashingTF的情况下,它是维度降低,具有 * 可能的冲突
这对于相对 * 低 *(
pow(2,4)
,pow(2,8)
)的显式numFeatures
值尤其是个问题;默认值是相当 * 高 *(pow(2,20)
)在这个例子中:输出包含16个“哈希桶”(因为我使用了
numFeatures=pow(2,4)
)虽然我的输入有10个唯一的令牌,* 输出只创建8个唯一的哈希 *(由于哈希冲突);
哈希冲突意味着3个不同的令牌被赋予相同的哈希,(即使所有令牌都是唯一的;且仅应发生1x)
(So保留默认值
numFeatures
或increase yournumFeatures
to try to avoid collisions:这种[散列]方法避免了计算全局术语到索引Map的需要,这对于大型语料库来说可能是昂贵的,但它遭受潜在的散列冲突,其中不同的原始特征在散列后可能变成相同的术语。为了减少碰撞的机会,我们可以增加目标特征维度,即哈希表的桶数。
其他API差异
CountVectorizer
构造函数(即初始化时)支持额外的参数:minDF
minTF
CountVectorizerModel
有一个vocabulary
成员,所以你可以看到生成的vocabulary
(如果你fit
你的CountVectorizer
特别有用):countVectorizerModel.vocabulary
>>> [u'one', u'two', ...]
CountVectorizer
是“可逆的”,正如主要答案所说!使用它的vocabulary
成员,它是一个将索引项Map到(sklearn
'sCountVectorizer
does something similar)项的数组