多个分类特征(列)的特征哈希化

10

我想将特征“Genre”哈希成6列,并将特征“Publisher”单独哈希成另外6列。我想要的结果如下所示:

      Genre      Publisher  0    1    2    3    4    5      0    1    2    3    4    5 
0     Platform  Nintendo  0.0  2.0  2.0 -1.0  1.0  0.0    0.0  2.0  2.0 -1.0  1.0  0.0
1       Racing      Noir -1.0  0.0  0.0  0.0  0.0 -1.0   -1.0  0.0  0.0  0.0  0.0 -1.0
2       Sports     Laura -2.0  2.0  0.0 -2.0  0.0  0.0   -2.0  2.0  0.0 -2.0  0.0  0.0
3  Roleplaying      John -2.0  2.0  2.0  0.0  1.0  0.0   -2.0  2.0  2.0  0.0  1.0  0.0
4       Puzzle      John  0.0  1.0  1.0 -2.0  1.0 -1.0    0.0  1.0  1.0 -2.0  1.0 -1.0
5     Platform      Noir  0.0  2.0  2.0 -1.0  1.0  0.0    0.0  2.0  2.0 -1.0  1.0  0.0

下面的代码实现了我想要做的事情

import pandas as pd
d = {'Genre': ['Platform', 'Racing','Sports','Roleplaying','Puzzle','Platform'], 'Publisher': ['Nintendo', 'Noir','Laura','John','John','Noir']}
df = pd.DataFrame(data=d)
from sklearn.feature_extraction import FeatureHasher
fh1 = FeatureHasher(n_features=6, input_type='string')
fh2 = FeatureHasher(n_features=6, input_type='string')
hashed_features1 = fh.fit_transform(df['Genre'])
hashed_features2 = fh.fit_transform(df['Publisher'])
hashed_features1 = hashed_features1.toarray()
hashed_features2 = hashed_features2.toarray()
pd.concat([df[['Genre', 'Publisher']], pd.DataFrame(hashed_features1),pd.DataFrame(hashed_features2)],
          axis=1)

这对于前面两个特征有效,但是如果我有40个分类特征,那么这种方法将会很繁琐。是否还有其他方式可以做到?


1
非常好的第一个问题 - 我添加了一些标签,以便它暴露给具有正确技能集的人。 - Patrick Artner
40个分类特征指的是40列分类数据吗? - Bharath M Shetty
是的,有40列分类数据。 - Noor
谢谢Patrick Artner。 - Noor
2个回答

6

哈希(更新)

假设一些新类别可能会出现在某些特征中,哈希是解决这个问题的方法。只需要注意以下两点:

  • 要意识到可能发生碰撞,并相应地调整特征数量。
  • 在您的情况下,您需要分别对每个特征进行哈希。

独热向量

如果每个特征的类别数量是固定且不太大的,请使用独热编码。

我建议使用以下两种方法之一:

  1. sklearn.preprocessing.OneHotEncoder
  2. pandas.get_dummies

示例

import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.feature_extraction import FeatureHasher
from sklearn.preprocessing import OneHotEncoder

df = pd.DataFrame({'feature_1': ['A', 'G', 'T', 'A'],
                   'feature_2': ['cat', 'dog', 'elephant', 'zebra']})

# Approach 0 (Hashing per feature)
n_orig_features = df.shape[1]
hash_vector_size = 6
ct = ColumnTransformer([(f't_{i}', FeatureHasher(n_features=hash_vector_size, 
                        input_type='string'), i) for i in range(n_orig_features)])

res_0 = ct.fit_transform(df)  # res_0.shape[1] = n_orig_features * hash_vector_size

# Approach 1 (OHV)
res_1 = pd.get_dummies(df)

# Approach 2 (OHV)
res_2 = OneHotEncoder(sparse=False).fit_transform(df)

res_0 :

array([[ 0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  1., -1.,  0., -1.],
       [ 0.,  0.,  0.,  1.,  0.,  0.,  0.,  2., -1.,  0.,  0.,  0.],
       [ 0., -1.,  0.,  0.,  0.,  0., -2.,  2.,  2., -1.,  0., -1.],
       [ 0.,  0.,  0.,  0.,  1.,  0.,  0.,  2.,  1., -1.,  0., -1.]])

res_1 :

   feature_1_A  feature_1_G  feature_1_T  feature_2_cat  feature_2_dog  feature_2_elephant  feature_2_zebra
0            1            0            0              1              0                   0                0
1            0            1            0              0              1                   0                0
2            0            0            1              0              0                   1                0
3            1            0            0              0              0                   0                1

res_2 :

array([[1., 0., 0., 1., 0., 0., 0.],
       [0., 1., 0., 0., 1., 0., 0.],
       [0., 0., 1., 0., 0., 1., 0.],
       [1., 0., 0., 0., 0., 0., 1.]])

1
不,我不能使用独热编码,因为我是按块处理数据的,可能会出现新的块包含一些在第一个块中不存在的特征的分类值。在这种情况下,独热编码将生成比第一个块更多的列。由于我需要将数据应用于partial_fit分类器,所以每次迭代都需要相同数量的列。请参阅此链接(https://stackoverflow.com/questions/54096164/how-to-sent-additional-unique-categorical-values-of-features-to-partial-fit-of-s?noredirect=1#comment95116600_54096164) - Noor
你的代码非常有帮助。谢谢。但是你说要“注意可能发生的碰撞并相应调整特征数量”。所以如果有40个特征列,每一列都可能需要哈希到不同数量的列。例如在你的代码中,我想让feature_1哈希到大小为6的向量(hash_vector_size = 6),feature_2哈希到大小为5的向量(hash_vector_size = 5)。我该如何修改代码呢?附注:我尝试过自己修改,但没有成功。 - Noor
1
我会创建一个字典,其中键是原始特征名称,列是给定特征的hash_vector_size。然后在实例化ColumnTransformer时简单地使用这个字典。请参阅文档中的“transformers”参数:https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html#sklearn.compose.ColumnTransformer - Jan K
1
我已按照您的建议完成了以下编程任务。我想它应该是可以工作的。ct = ColumnTransformer([(f't_{i_key}', FeatureHasher(n_features=i_value, input_type='string'), i_key) for i_key, i_value in dict_hashed_vector_size.items()]) - Noor
关于Approach 0有一些奇怪的地方。正如您在结果中看到的那样,它会为第一行生成4个指数,而不是2个。我也期望得到2个指标,因为有2个不同的列。原因是,如果您使用特征散列器,并且输入类型为'string',则它会期望字符串列表。如果您只输入一个字符串,则每个字符都将被散列。因此,对于第一行['A','cat'],您会获得4个指数,而不是2个指数。 - filthysocks

2
尽管我来得有点晚,在Kaggle上看到的示例表明,FeatureHashing是针对多个列(即在DataFrame上)一次执行的,而不是针对单个列并连接稀疏矩阵。请参考Kaggle上的笔记本,这里这里。我也使用了两种方法在这个数据上执行功能哈希,即:

a. 哈希各自的分类列并连接结果
b. 一次哈希DataFrame的所有分类列

当采用(b)方法时,逻辑回归分类器给出的结果明显更好,而不是采用(a)方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接