了解 FeatureHasher、碰撞和向量大小的权衡

Posted

技术标签:

【中文标题】了解 FeatureHasher、碰撞和向量大小的权衡【英文标题】:Understanding FeatureHasher, collisions and vector size trade-off 【发布时间】:2021-03-14 10:21:24 【问题描述】:

在实施机器学习模型之前,我正在预处理我的数据。一些特征具有高基数,例如国家和语言。

由于将这些特征编码为 one-hot-vector 会产生稀疏数据,因此我决定研究 the hashing trick 并像这样使用 python 的 category_encoders:

from category_encoders.hashing import HashingEncoder
ce_hash = HashingEncoder(cols = ['country'])
encoded = ce_hash.fit_transform(df.country)
encoded['country'] = df.country
encoded.head()

查看结果时,我可以看到碰撞

    col_0  col_1  col_2  col_3  col_4  col_5  col_6  col_7 country
0       0      0      1      0      0      0      0      0      US <━┓
1       0      1      0      0      0      0      0      0      CA.  ┃ US and SE collides 
2       0      0      1      0      0      0      0      0      SE <━┛
3       0      0      0      0      0      0      1      0      JP

进一步调查将我带到this Kaggle article。 Hashing 的例子包括 X 和 y

y 的目的是什么,它是否有助于解决碰撞问题? 我是否应该向编码器添加更多列并将多个特征一起编码(例如国家和语言)?

希望了解如何使用散列技巧对此类类别进行编码。

更新: 根据我从@CoMartel 获得的 cmets,我查看了Sklearn FeatureHasher 并编写了以下代码来对国家列进行哈希处理:

from sklearn.feature_extraction import FeatureHasher
h = FeatureHasher(n_features=10,input_type='string')
f = h.transform(df.country)
df1 = pd.DataFrame(f.toarray())
df1['country'] = df.country
df1.head()

得到以下输出:

     0    1    2    3    4    5    6    7    8    9 country
0 -1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0 -1.0  0.0      US
1 -1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0 -1.0  0.0      US
2 -1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0 -1.0  0.0      US
3  0.0 -1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0      CA
4  0.0  0.0  0.0  0.0  0.0  0.0  0.0  1.0 -1.0  0.0      SE
5  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0      JP
6 -1.0  0.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0      AU
7 -1.0  0.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0      AU
8 -1.0  0.0  0.0  0.0  0.0  0.0  1.0  0.0  0.0  0.0      DK
9  0.0  0.0  0.0  0.0  0.0  0.0  0.0  1.0 -1.0  0.0      SE
这是使用库来编码高分类的方式吗? 价值观? 为什么有些值是负数? 您将如何选择“正确的”n_features 值? 如何查看碰撞率?

【问题讨论】:

看source code,y似乎只是为了保持与sklearn的兼容性而存在。请注意,您的示例已有 2 年历史,sklearn 集成了自己的 FeatureHasher。 y 也未使用。简单示例:from sklearn.feature_extraction import FeatureHasher h = FeatureHasher(n_features=15) f = h.fit_transform(df[['country']].to_dict(orient='records')) f.toarray() 添加更多列对我的示例不起作用(即使使用 n_cols > 基数也会发生冲突),但在我的情况下,同时编码 2 列似乎可以纠正冲突。我试过:df = pd.DataFrame([_ for _ in 'abcdefghij'],columns=['country']) 分组编码的第二列:df['language'] = [_ for _ in 'abcdefghij'[::-1]] 【参考方案1】:

这是使用库来编码高分类的方式吗? 价值观?

是的。您的实施没有任何问题。

您可以将散列技巧视为“具有较小碰撞风险的缩减大小的 one-hot 编码,如果您可以容忍原始特征维度,则不需要使用它” .

这个想法最初是由Kilian Weinberger 提出的。你可以在他们的论文中找到对算法的理论和实践/经验的整体分析。


为什么有些值是负数?

为避免冲突,使用了 signed 哈希函数。也就是说,首先使用通常的hash function 对字符串进行哈希处理(例如,通过将每个字符的 ASCII 值相加,将字符串转换为相应的数值,然后对n_feature 取模以在 (0, n_features ])。然后使用另一个单比特输出散列函数。后者根据定义生成+1-1,它被添加到由第一个哈希函数。

伪代码(虽然看起来像 Python):

def hash_trick(features, n_features):
     for f in features:
         res = np.zero_like(features)
         h = usual_hash_function(f) # just the usual hashing
         index = h % n_features  # find the modulo to get index to place f in res
         if single_bit_hash_function(f) == 1:  # to reduce collision
             res[index] += 1
         else:
             res[index] -= 1 # <--- this will make values to become negative

     return res 

你会如何选择“正确的”n_features 值?

根据经验,您可以猜到,如果我们散列一个额外的特征(即#n_feature + 1),肯定会发生冲突。因此,最好的情况是每个特征都映射到一个唯一的哈希值——希望如此。在这种情况下,从逻辑上讲,n_features 应该至少等于功能/类别的实际数量(在您的特定情况下,不同国家的数量)。尽管如此,请记住这是“最好的”情况,而不是“数学上”的情况。因此,越高越好当然,但多高呢?见下。


如何查看碰撞率?

如果我们忽略第二个单比特哈希函数,问题就会简化为“哈希生日问题”。

这是一个很大的话题。对于这个问题的全面介绍,我推荐你阅读this,对于一些详细的数学,我推荐this答案。

简而言之,您需要知道的是,没有碰撞的概率是exp(-1/2) = 60.65%,这意味着大约有39.35% 的概率至少会发生一次碰撞。

因此,根据经验,如果我们有X 个国家/地区,如果哈希函数输出范围(即n_feature 参数)为X^2,则至少有一次碰撞的概率约为40% .换句话说,如果您的示例中的国家/地区数量 = square_root(n_features),则有 40% 发生冲突的可能性。随着您以指数方式增加n_features,碰撞的机会减少了一半。 (个人而言,如果不是出于安全目的,而只是从字符串到数字的普通转换,则不值得太高。

古玩读者的旁注:对于足够大的散列函数输出大小(例如 256 位),攻击者猜测(或利用)冲突的机会几乎是不可能的(从安全角度来看)。


关于y 参数,正如您已经在评论中得到的那样,它只是出于兼容性目的,未使用(scikit-learn 与许多其他实现一起使用)。

【讨论】:

以上是关于了解 FeatureHasher、碰撞和向量大小的权衡的主要内容,如果未能解决你的问题,请参考以下文章

FeatureHasher使用方法详解

sklearn FeatureHasher中的哈希技巧

使用向量的突破碰撞检测

sklearn使用FeatureHasher处理字符串特征

使用向量进行简单的 2D 碰撞检测

鼠标坐标到 3D 世界/投影以进行点碰撞