影响机器学习效果可能的原因:算法 / 数据处理的怎么样(特征工程)

为什么需要特征工程(Feature Engineering)

数据和特征决定了机器学习的上限,模型和算法只是逼近这个上限而已。

吴恩达老师说:Coming up with features is difficult, time-consuming, requires expert knowledge, “Applied machine learning” is basically feature engineering.

特征工程是使用专业背景知识和技巧处理数据,是的特征能在机器学习算法上发挥更好的作用的过程。意义:会直接影响机器学习的效果。

  • Pandas:一般用来数据清洗和数据处理
  • SkLearn:用来进行特征工程

特征工程包含内容:

特征抽取 / 特征提取

假设对一篇短文做文章分类,想要用机器学习的算法去做,会出现什么问题?机器学习算法[注1]是数学公式,无法处理字符串,所以需要对数据集进行转换成数值。将任意数据(如文本或图像)转换为可用于机器学习的数字特征。

特征值化是为了计算机更好的去理解数据

  • 字典特征提取(特征离散化)
  • 文本特征提取
  • 图像特征提取(这部分,深度学习将介绍)

我们可以使用 sklearn.feature_extraction api 进行特征提取

字典特征提取

作用:对字典数据进行特征值化

sklearn.feature_extraction.DictVectorizer(sparse=True, ...),理解为将字典进行向量化。将向量存储到计算机中(可以通过 矩阵(Matrix) 方法去存储,也就是变为 二维数组)。所以向量可以通过 一维数组 进行存储。

比如说我们有这么一个数据

data = [
{"city": "北京", "temperature": 100},
{"city": "上海", "temperature": 60},
{"city": "深圳", "temperature": 30}
]

那么转换后的数据会变成

['city=上海', 'city=北京', 'city=深圳', 'temperature']
[[ 0. 1. 0. 100.],
[ 1. 0. 0. 60.],
[ 0. 0. 1. 30.]]

为什么会转换成这个样子[注2]

所以字典特征读取实际上是将属于类别的特征转换成 OneHot 编码。

这个转换之后的父类就是一个 transform 转换器类,里面包含了一些方法:

  • DictVectorizer.fit_transform(x)
    • x: 字典或者包含字典的迭代器返回值
    • 返回 sparse 矩阵[注3]
  • DictVectorizer.inverse_transform(x)
    • x: array 数组或者 sparse 矩阵
    • 返回值:转换之前的数据格式
  • DictVectorizer.get_feature_names()
    • 返回类别名称

字典特征抽取的应用场景:

  1. 数据集当中,类别特征比较多的情况下,将数据集的特征转换成字典类型,再用 DictVectorizer 进行转换
  2. 拿到的数据就是数据的话,那就用字典特征抽取

文本特征抽取

用单词作为特征

特征预处理

特征降维

注释

[注1] 机器学习算法:机器学习是一群高统计学的人使用统计方法搞出来的,所以涉及到的都是数学公式。要将一些非数学的数据进行处理,我们需要:

  • 文本类型 转换成 数值
  • 类型 转换成 数值

[注2] 为什么会转换成那样的矩阵的解释。我们看回原始数据(字典),每个样本有两个特征。按理来说应该转换为三行两列的矩阵。但是实际上我们转换得到的是三行四列的矩阵(样本量不变,特征量变成了 4 个)。当特征中有类别(北京、上海、深圳)的表示方式为字符串,想表示为数值,并且没有数值上大小差别的数据,就需要用 OneHot 编码 / 哑变量。实际上可以理解为这样的一个表:

city=上海 city=北京 city=深圳 temperature
0 1 0 100
1 0 0 60
0 0 1 30

[注3] 为什么是返回 spouse 矩阵?spouse 矩阵是什么?当我们执行代码

from sklearn.feature_extraction import DictVectorizer

data = [
{"city": "北京", "temperature": 100},
{"city": "上海", "temperature": 60},
{"city": "深圳", "temperature": 30}
]
# 1. 实例化一个转换器类
transform = DictVectorizer()

# 2. 调用 fit_transform 方法,传入包含字典的迭代器
data_new = transform.fit_transform(data)

print(data_new)

时,返回值是这样的:

(0, 1)        1.0
(0, 3) 100.0
(1, 0) 1.0
(1, 3) 60.0
(2, 2) 1.0
(2, 3) 30.0

这是稀疏矩阵(Sparse Matrix),为什么要返回这种形式?当我们调用 sklearn.feature_extraction.DictVectorizer(sparse=True, ...) ,默认就返回 sparse 矩阵。如果需要还原成我们想看到比较直观的,可以在实例化转换器类时,这样写:transform = DictVectorizer(sparse=False)。这样,返回值就会变成:

[[  0.   1.   0. 100.]
[ 1. 0. 0. 60.]
[ 0. 0. 1. 30.]]

可以看到,其实 sparse 矩阵的左侧时位置,右侧是值。稀疏矩阵将非零值按位置表示出来,这样存储显而易见的比较节省内存,提高加载效率