为了理解“哈希技巧”,我编写了以下测试代码:
import pandas as pdfrom sklearn.feature_extraction import FeatureHashertest = pd.DataFrame({'type': ['a', 'b', 'c', 'd', 'e','f','g','h']})h = FeatureHasher(n_features=4, input_type='string')f = h.transform(test.type)print(f.toarray())
在上面的例子中,我将8个类别映射到4列,输出结果是:
[[ 0. 0. 1. 0.]<-a [ 0. -1. 0. 0.]<-b [ 0. -1. 0. 0.]<-c [ 0. 0. 0. 1.]<-d [ 0. 0. 0. 1.]<-e [ 0. 0. 0. 1.]<-f [ 0. 0. -1. 0.]<-g [ 0. -1. 0. 0.]]<-g
在结果矩阵中,我可以看到重复的情况,有些类别以相同的方式表示。这是为什么呢?如果使用二进制表示法,8个类别可以映射到4列。
能有人解释一下这种技术的输出,并详细阐述一下吗?
回答:
如果将n_features
设置为如此低的值,FeatureHasher
会导致不理想的结果。其原因在于它将类别映射到列索引的方式。
与CountVectorizer
不同,后者根据出现顺序为每个类别分配一个唯一整数索引对应一列,FeatureHasher
会对特征应用哈希函数来确定每个类别的列索引。其主要优势因此是速度提升。然而,通过将n_features
限制为如此低的值,给定类别的哈希结果很可能导致一个索引高于设置的n_features
,结果你得到的是一个截断的特征向量。
我们实际上可以通过重现_hashing_fast
中的哈希方式来检查这一点,它使用murmurhash3_bytes_s32
来生成哈希值:
from sklearn.utils.murmurhash import murmurhash3_bytes_s32raw_X = test['type']raw_X = iter(raw_X)raw_X = (((f, 1) for f in x) for x in raw_X)for x in raw_X: for f, v in x: f = f'{f}={v}' fb = (f).encode("utf-8") h = murmurhash3_bytes_s32(fb, seed=0) print(f'{f[0]} -> {h}')
正如你所见,确切地为e
和f
产生了较大的哈希值,这些值被截断为与d
对应的较低哈希值:
a -> -424864564b -> -992685778c -> -1984769100d -> 728527081e -> 2077529484f -> 2074045163g -> -1877798433h -> -51608576