如何处理传统机器学习中的字符串特征数组?

14

问题

假设我们有一个看起来像这样的数据框:

age  job         friends                                    label
23   'engineer'  ['World of Warcraft', 'Netflix', '9gag']   1
35   'manager'   NULL                                       0
...

如果我们有兴趣训练一个分类器,使用年龄工作朋友作为特征来预测标签,那么我们应该如何将这些特征转换成可以输入模型的数字数组呢?

  • 年龄很简单,因为它已经是数字了。
  • 工作可以进行哈希/索引,因为它是一个分类变量。
  • 朋友是一个分类变量列表。我应该怎么表示这个特征呢?

方法:

对列表中的每个元素进行哈希处理。假设我们的哈希函数具有以下映射,使用示例数据框:

NULL                -> 0
engineer            -> 42069
World of Warcraft   -> 9001
Netflix             -> 14
9gag                -> 9
manager             -> 250
 

假设朋友列表的最大长度是5。如果朋友列表长度小于5,则在右侧填充零。如果朋友列表长度大于5,则选择前5个元素。

方法1:哈希和堆栈

特征转换后的数据框如下所示:

feature                             label
[23, 42069, 9001, 14, 9, 0, 0]      1
[35, 250,   0,    0,  0, 0, 0]      0

限制

考虑以下内容:

age  job           friends                                        label
23   'engineer'    ['World of Warcraft', 'Netflix', '9gag']       1
35   'manager'      NULL                                          0
26   'engineer'    ['Netflix', '9gag', 'World of Warcraft']       1
...

比较第一条和第三条记录的功能:

feature                             label
[23, 42069, 9001, 14, 9, 0, 0]      1
[35, 250,   0,    0,  0, 0, 0]      0
[26, 42069, 14,    9, 9001, 0]      1

这两个记录有相同的朋友集合,但由于排序不同,导致特征哈希不同,尽管它们应该是相同的。

方法2:哈希、排序和堆叠

为了解决方法1的限制,只需按照 朋友 特征的哈希值进行排序即可。这将导致以下特征转换(假设按降序排列):

feature                             label
[23, 42069, 9001, 14, 9, 0, 0]      1
[35, 250,   0,    0,  0, 0, 0]      0
[26, 42069, 9001, 14, 9, 0, 0]      1

这种方法也有限制。考虑以下情况:

age  job           friends                                        label
23   'engineer'    ['World of Warcraft', 'Netflix', '9gag']       1
35   'manager'      NULL                                          0
26   'engineer'    ['Netflix', '9gag', 'World of Warcraft']       1
42   'manager'     ['Netflix', '9gag']                            1
...

应用特征变换并进行排序,我们得到:

row  feature                             label
1    [23, 42069, 9001, 14, 9, 0, 0]      1
2    [35, 250,   0,    0,  0, 0, 0]      0
3    [26, 42069, 9001, 14, 9, 0, 0]      1
4    [44, 250, 14, 9, 0, 0, 0]           1

以上特征存在什么问题?好吧,第1行和第3行的Netflix和9gag哈希在数组中具有相同的索引,但在第4行却没有。这会影响训练结果。
方法3:将数组转换为列
如果我们将“朋友”转换为5列,并像处理任何分类变量一样处理每个结果列,会怎么样?
嗯,假设“朋友”的词汇量很大(>100k)。那么去创建>100k的列,其中每个列负责相应词汇元素的哈希值,就太疯狂了。
方法4:独热编码再求和
如何处理这种情况?将每个哈希转换为独热向量,然后将所有这些向量相加。
例如,在这种情况下,第1行的特征会是这样的:
[23, 42069, 01x8, 1, 01x4, 1, 01x8986, 1, 01x(max_hash_size-8987)]

其中01x8表示一个由8个零组成的行。

这种方法的问题在于,这些向量将非常庞大且稀疏。

方法5:使用嵌入层和1D-Conv

使用此方法,我们将friends数组中的每个单词馈送到嵌入层中,然后进行卷积。与Keras IMDB示例类似:https://keras.io/examples/imdb_cnn/

限制:需要使用深度学习框架。我想要一个可以与传统机器学习一起使用的方法。我想要做逻辑回归或决策树。

你对此有何想法?


我目前正在研究稀疏数据表示,我认为这可能有助于处理第四种方法的限制。 - tooskoolforkool
在几行Python代码中,可以使用预训练的词嵌入将您的单词列表转换为向量列表。这打开了进一步准备数据以用于传统ML模型的方式,但它是否符合您的“适用于传统机器学习”的标准?无需训练神经网络,但您需要导入(例如)tensorflow来执行嵌入。如果您感兴趣,我可以详细解释这个问题。 - David Harris
4个回答

3
如另一个答案所提到的,您已经列出了一些备选方案,具体取决于数据集和模型等因素。
就我所知,典型的逻辑回归模型会使用第三种方法,将每个朋友字符串转换为二进制特征。如果您不想有10万个特征,可以像词袋模型一样处理这些特征,并且舍弃停用词(非常常见的特征)。
我还会混合一种哈希变量: 布隆过滤器 您可以为每个训练示例在布隆过滤器中存储相关字符串,并将布隆过滤器的位作为逻辑回归模型中的特征。这基本上是一个类似于您已经提到的哈希解决方案,但它处理了一些索引/排序问题,并提供了更加原则性的稀疏性和特征唯一性之间的权衡。

2

首先,这个问题没有确定的答案,你提出了5个方案,这五个方案都是有效的,最终选择哪一个方案取决于你所使用的数据集。

鉴于此,我将列出我认为最有优势的选项。对于我来说,第五个选项是最好的选择,但由于您想使用传统的机器学习技术,我会放弃它。因此,我会选择第四个选项,但在这种情况下,我需要知道你是否有足够的硬件来处理这个问题。如果答案是肯定的,那么我会选择这个选项,如果答案是否定的,我会尝试第二种方法,正如你所指出的,Netflix和9gag的哈希值在数组的第1行和第3行中具有相同的索引,但在第4行中不是,但如果你有足够的训练数据,那就不会成为问题(再次强调,这完全取决于可用的数据),即使我对这种方法有一些问题,我也会在放弃之前应用数据增强技术。

我认为选项1是最糟糕的,使用它有很大的过拟合风险,并且需要大量的计算资源。

希望这可以帮到你!


1
方法1(哈希和堆栈)和方法2(哈希、排序和堆栈)可以通过将哈希函数的结果视为稀疏向量中值为1的索引来解决它们的限制,而不是向量每个位置的值。
然后,无论“魔兽世界”在“friends”数组中的位置如何(方法1的限制),或者其他元素是否存在于“friends”数组中(方法2的限制),只要“魔兽世界”在“friends”数组中,“feature vector”中的9001位置就会有一个值为1。如果“魔兽世界”不在“friends”数组中,则特征向量中9001位置的值很可能为0(查找哈希技巧碰撞以了解更多信息)。

0

使用word2vec表示(作为特征值),然后进行监督分类也是一个不错的想法。


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