机器学习之混合类型数据的使用

在机器学习中,经常会碰到不同类型的数据(numeric, categorical, Continuous and Text data)混合使用的情况,而机器学习算法一般只接受数值型的数据。比如说,虽然神经网络很强大,但是也没办法直接处理类别型的变量,需要经过如one-hot编码的预处理之后才能放进网络去训练。因此,必须对这些数据进行预处理。但是,不同的处理方式,可能对模型的效果产生重要的影响。

Understanding Categorical Data

类别型数据,主要有两种:Nominal(名称)、Ordinal(顺序)

名称型类别数据,在该属性的值之间没有排序的概念,如天气、城市等。

这里写图片描述

顺序分类特征,它的值的大小是有一定意义的(如衬衫尺寸、鞋子大小、学历高低等)

这里写图片描述

Feature Engineering on Categorical Data

通常,特征工程中的标准工作流都涉及到将这些类别值经某种形式的转换,转化为数字标签的形式,然后在这些值上应用一些编码方案。

Transforming Nominal Attributes

数据来源:kaggle videogames

这里写图片描述

游戏类别字段Genre和Publisher、Platform都是名称属性。

查看游戏类别有多少类

genres = np.unique(vg_df['Genre'])
genres
Output
------
array(['Action', 'Adventure', 'Fighting', 'Misc', 'Platform',  
       'Puzzle', 'Racing', 'Role-Playing', 'Shooter', 'Simulation',  
       'Sports', 'Strategy'], dtype=object)

通过利用scikit-learn来生成一个标签编码方案,将每个类别映射到一个数值。

from sklearn.preprocessing import LabelEncoder
gle = LabelEncoder()
genre_labels = gle.fit_transform(vg_df['Genre'])
genre_mappings = {index: label for index, label in 
                  enumerate(gle.classes_)}
genre_mappings

Output
------
{0: 'Action', 1: 'Adventure', 2: 'Fighting', 3: 'Misc',
 4: 'Platform', 5: 'Puzzle', 6: 'Racing', 7: 'Role-Playing',
 8: 'Shooter', 9: 'Simulation', 10: 'Sports', 11: 'Strategy'}
vg_df['GenreLabel'] = genre_labels
vg_df[['Name', 'Platform', 'Year', 'Genre', 'GenreLabel']].iloc[1:7]

这里写图片描述

GenreLabel作为属性使用时,还需要对它进行额外的编码才能使用,因为它们不应该存在大小的关系。

Transforming Ordinal Attributes

数据来源:kaggle Pokémon dataset

poke_df = pd.read_csv('datasets/Pokemon.csv', encoding='utf-8')
poke_df = poke_df.sample(random_state=1, frac=1).reset_index(drop=True)
np.unique(poke_df['Generation'])
Output
------
array(['Gen 1', 'Gen 2', 'Gen 3', 'Gen 4', 'Gen 5', 'Gen 6'], dtype=object)

妖怪有6个世代,每个妖怪属于其中一个世代。这是特征是有顺序的,在游戏中,第一代的“口袋妖怪”比第二代更早出现。

这里写图片描述

一般情况下,没有通用的模块或函数来映射和将这些特性转换为基于顺序的数字表示。因此,可以使用自定义编码\映射方案。

gen_ord_map = {'Gen 1': 1, 'Gen 2': 2, 'Gen 3': 3, 'Gen 4': 4, 'Gen 5': 5, 'Gen 6': 6}
poke_df['GenerationLabel'] = poke_df['Generation'].map(gen_ord_map)
poke_df[['Name', 'Generation', 'GenerationLabel']].iloc[4:10]

这里写图片描述

Encoding Categorical Attributes

至此,已经将类别转换为数字标签,为什么还需要编码?

比如,对于电子游戏种类来说,如果直接将GenreLabel喂给机器学习模型,模型会认为它是连续的数字特征,同时会认为10(sports)会比6(Racing)大,但是这个大小是没有意义的,不能直接比较大小。因此,需要一种额外的编码方案,即在每个特征的所有不同值中,为每个独特的值创建虚拟特性(哑变量)。

One-hot Encoding Scheme

这里写图片描述

Dummy Coding Scheme

这里写图片描述

当一个特征中,类别很多时,采用上述的编码方式,会存在维数灾难的问题。此时可以使用区间计数方案(Bin-counting Scheme),如分箱操作。

text data

对于文本数据,同样需要将文本转化为向量的形式才能被机器学习模型处理,处理的方法主要有:

  • 词袋模型(Bag of Word)

这应该是非结构化文本中最简单的向量空间表示法。向量的每个维度都是特定的特征/属性。词袋模型将每个文本文档表示为数值向量,其中维度是来自语料库的一个特定的词,而该维度的值可以用来表示这个词在文档中的出现频率、是否出现(由0和1表示),或者加权值。将这个模型叫做词袋模型,是因为每个文档可以看作是装着单词的袋子,而无须考虑单词的顺序和语法。当语料规模比较大时,会存在维数灾难的问题,而且该方法没有考虑语义。

这里写图片描述

  • N元词袋模型(Bag of N-Gram Model)

一个单词是一个标记,通常被称为单元(unigram)或者一元(1-gram)。词袋模型不考虑单词的顺序,但是如果我们想要考虑序列中出现的短语或者词汇集合呢?N元模型能够帮我们实现这一点。N-Gram是来自文本文档的单词记号的集合,这些记号是连续的,并以序列的形式出现。二元表示阶数为二的N-Gram,也就是两个单词。同理三元表示三个单词。N元词袋模型是普通词袋模型的一种拓展,使得我们可以利用基于N元的特征。

这里写图片描述

  • TF-IDF 模型

在大型语料库中使用词袋模型可能会出现一些潜在的问题。由于特征向量是基于词的频率,某些单词可能会在文档中频繁出现,这可能会在特征集上掩盖掉其他单词。TF-IDF模型试图通过缩放或者在计算中使用归一化因子来解决这个问题。TF-IDF 即 Term Frequency-Inverse Document Frequency,在计算中结合了两种度量:词频(Term Frequency)和逆文档频率(Inverse Document Frequency)。这种技术是为搜索引擎中查询排序而开发的,现在它是信息检索和 NLP 领域中不可或缺的模型。

这里写图片描述

  • 主题模型

也可以使用一些摘要技术从文本中提取主题或者基于概念的特征。主题模型围绕提取关键主题或者概念。每个主题可以表示为文档语料库中的一个词袋或者一组词。总之,这些术语表示特定的话题、主题或概念,凭借这些单词所表达的语义含义,可以轻松将每个主题与其他主题区分开来。这些概念可以从简单的事实、陈述到意见、前景。主题模型在总结大量文本来提取和描绘关键概念时非常有用。它们也可用于从文本数据中捕捉潜在的特征。

这里写图片描述

  • 神经网络(word embedding)

word2vec、doc2vec、glove

多种类型数据的混合使用

  • 将文本数据用tf-idf或其它文本表示方法转化为向量

  • dummy或其它方法将类别型变量转化为数值型

    此时,所有的数据都转化为了数值型。

  • 将所有的特征进行组合

参考

[1] Understanding Feature Engineering (Part 2) — Categorical Data

猜你喜欢

转载自blog.csdn.net/extremebingo/article/details/80402312