数据预处理与特征工程

学习地址

课件
scikit-learn (sklearn) 官方文档中文版
scikit-learn (sklearn) 官方文档中文版
特征缩放(Feature Scaling)
使用sklearn做单机特征工程
特征工程到底是什么?


概述

数据不给力,再高级的算法能无能为力。

数据挖掘的五大流程:

  1. 获取数据
  2. 数据预处理
    数据预处理是从数据中检测,纠正或删除损坏,不准确或不适用于模型的记录的过程
    可能面对的问题有:数据类型不同,比如有的是文字,有的是数字,有的含时间序列,有的连续,有的间断。也可能,数据的质量不行,有噪声,有异常,有缺失,数据出错,量纲不一,有重复,数据是偏态,数据量太大或太小
    数据预处理的目的:让数据适应模型,匹配模型的需求
  3. 特征工程
    特征工程是将原始数据转换为更能代表预测模型的潜在问题的特征的过程,可以通过挑选最相关的特征,提取特征以及创造特征来实现。其中创造特征又经常以降维算法的方式实现。
    可能面对的问题有:特征之间有相关性,特征和标签无关,特征太多或太小,或者干脆就无法表现出应有的数据现象或无法展示数据的真实面貌
    特征工程的目的:1) 降低计算成本,2) 提升模型上限
  4. 建模,测试模型并预测出结果
  5. 上线,验证模型效果

sklearn中的数据预处理和特征工程

  • sklearn.preprocessing模块:几乎包含数据预处理的所有内容
  • sklearn.impute模块:填补缺失值专用
  • sklearn.feature_selection模块:包含特征选择的各种方法的实践
  • sklearn.decomposition模块:包含降维算法

数据预处理

数据无量纲化

在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”。
无量纲化可以加快求解速度,可以帮我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响。

数据的无量纲化可以是线性的,也可以是非线性的。线性的无量纲化包括中心化(Zero-centered或者Meansubtraction)处理和缩放处理(Scale)。中心化的本质是让所有记录减去一个固定值,即让数据样本数据平移到某个位置。缩放的本质是通过除以一个固定值,将数据固定在某个范围之中,取对数也算是一种缩放处理。

  • preprocessing.MinMaxScaler
    当数据(x)按照最小值中心化后,再按极差(最大值 - 最小值)缩放,数据移动了最小值个单位,并且会被收敛到
    [0,1]之间,而这个过程,就叫做数据归一化(Normalization,又称Min-Max Scaling)。注意,Normalization是归
    一化,不是正则化,真正的正则化是regularization,不是数据预处理的一种手段。归一化之后的数据服从正态分布
    归一化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    import numpy as np
    from sklearn.preprocessing import MinMaxScaler

    data=np.array([[1,3],[2,4],[4,1],[2,5]])
    print(data.shape) # (4,2)

    # 实现归一化
    scaler=MinMaxScaler() # 实例化,默认范围[0-1]
    result=scaler.fit_transform(data) # 直接生成结果
    print(result)
    '''
    [[0. 0.5 ]
    [0.33333333 0.75 ]
    [1. 0. ]
    [0.33333333 1. ]]
    # 实际上上述步骤可拆分成.fit()和.transform()两步,fit()本质是生成min(x)和max(x)
    '''

    # 结果逆转,生成原始数据
    data=scaler.inverse_transform(result)
    print(data)
    '''
    [[1. 3.]
    [2. 4.]
    [4. 1.]
    [2. 5.]]
    '''

    # 归一化到指定范围
    data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
    scaler=MinMaxScaler(feature_range=[5,10])
    result=scaler.fit_transform(data)
    print(result)
    '''
    [[ 5. 5. ]
    [ 6.25 6.25]
    [ 7.5 7.5 ]
    [10. 10. ]]
    '''

注: 如果待预处理数据X中特征非常多,使用.fit接口可能会报错,因为数据量太大无法计算,可以使用.partial_fit接口实现同样功能。

当然,已知计算公式,也可以借助numpy利用矩阵运算对数据进行归一化处理。

  • preprocessing.StandardScaler
    当数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分布),而这个过程,就叫做数据标准化(Standardization,又称Z-score normalization)
    标准化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import numpy as np
    from sklearn.preprocessing import MinMaxScaler
    from sklearn.preprocessing import StandardScaler

    data=np.array([[1,3],[2,4],[4,1],[2,5]])
    scaler=StandardScaler() # 实例化
    scaler=scaler.fit(data) # 本质是生成均值和方差,按列
    print(scaler.mean_) # 查看均值 [2.25 3.25]
    print(scaler.var_) # 查看方差 [1.1875 2.1875]

    X_std=scaler.transform(data)
    print(X_std)
    '''
    [[-1.14707867 -0.16903085]
    [-0.22941573 0.50709255]
    [ 1.60591014 -1.52127766]
    [-0.22941573 1.18321596]]
    '''
    # result=scaler.fit_transform(data) # 一步达成结果
    # datascaler.inverse_transform(result)

注意:对于StandardScalerMinMaxScaler来说,空值NaN会被当做是缺失值,在fit的时候忽略,在transform的时候
保持缺失NaN的状态显示。
并且,尽管去量纲化过程不是具体的算法,但在fit接口中,依然只允许导入至少二维数组,一维数组导入会报错

  • StandardScaler和MinMaxScaler选哪个?
    大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择
    MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。
    各种缩放
缺失值处理
  • impute.SimpleImputer
    这个类是专门用来填补缺失值的。它包括四个重要参数:
参数 含义&输入
missing_values 告诉SimpleImputer,数据中的缺失值长什么样,默认空值np.nan
strategy 我们填补缺失值的策略,默认均值“mean”使用均值填补)(仅对数值型特征可用),“median”用中值填补( 对数值型特征可用),”most_frequent”用众数填补(对数值型和字符型特征都可用),“constant”表示请参考参 “fill_value”中的值(对数值型和字符型特征都可用
fill_value 当参数startegy为”constant”的时候可用,可输入字符串或数字表示要填充的值,常用0
copy 默认为True,将创建特征矩阵的副本,反之则会将缺失值填补到原本的特征矩阵中去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import numpy as np
import pandas as pd
from sklearn.impute import SimpleImputer

data=pd.read_csv('Data/Narrativedata.csv',index_col=0) # 指定第一列为索引读取数据
print(data.head())
'''
Age Sex Embarked Survived
0 22.0 male S No
1 38.0 female C Yes
2 26.0 female S Yes
3 35.0 female S Yes
4 35.0 male S No

'''

print(data.info())
'''
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
Age 714 non-null float64
Sex 891 non-null object
Embarked 889 non-null object
Survived 891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''
# 发现 Age、sex和Embarked具有空值

Age=data.loc[:,'Age'].values.reshape(-1,1) # 将series的值取出并生成二维的
_mean=SimpleImputer() # 实例化默认均值填充
_median=SimpleImputer(strategy='median') # 用中位数填充
_zero=SimpleImputer(strategy='constant',fill_value=0) # 用常数0填充,需要指定填充值
_most=SimpleImputer(strategy='most_frequent') # 使用众数填充

_mean=_mean.fit_transform(Age) # 一步完成调取结果
_median=_median.fit_transform(Age)
_zero=_zero.fit_transform(Age)
_most=_most.fit_transform(Age)

data.loc[:,'Age']=_median # 使用众数填充,也可以用填充好的_median、_zero或_most
print(data.info())
'''
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
Age 891 non-null float64
Sex 891 non-null object
Embarked 889 non-null object
Survived 891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''
# 发现Age字段的值全部非空,填充成功

当然,直接使用numpypandas填充也十分方便

处理分类型特征:编码与哑变量

在机器学习中,大多数算法,譬如逻辑回归,支持向量机SVM,k近邻算法等都只能够处理数值型数据,不能处理文字,在sklearn当中,除了专用来处理文字的算法,其他算法在fit的时候全部要求输入数组或矩阵,也不能够导入文字型数据。为了让数据适应算法和库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型

  • preprocessing.LabelEncoder: 标签专用,能够将分类转换为分类数值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import numpy as np
    import pandas as pd
    from sklearn.preprocessing import LabelEncoder

    data=pd.read_csv('Data/Narrativedata.csv',index_col=0) # 指定第一列为索引读取数据

    y=data.iloc[:,-1] # 取最后一列,标签允许一维
    le=LabelEncoder() # 实例化
    lable=le.fit_transform(y) # 一步生成,也可以拆分
    # y=le.inverse_transform(lable) # 也可以逆转
    data.iloc[:,-1]=lable
    print(data.head())
    '''
    Age Sex Embarked Survived
    0 22.0 male S 0
    1 38.0 female C 2
    2 26.0 female S 2
    3 35.0 female S 2
    4 35.0 male S 0
    '''
    # data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1]) # 熟悉之后也可以这样一步操作

fiit之后和.transform之前也可以用实例属性le.classes_查看标签中究竟有多少类别

  • preprocessing.OrdinalEncoder: 特征专用,能够将分类特征转换为分类数值
    1
    2
    3
    # 以下代码基于上述代码,即将空值全部填充完毕,否则报错
    _data=data.copy()
    _data.iloc[:,1:-1]=OrdinalEncoder().fit_transform(_data.iloc[:,1:-1])

这个类的用法和标签编码的用法基本一样的,但是如果要查看类别需要在.fit之后使用实例属性.categories_查看,注意同样需要在.transform之前查看,如果不需要查看直接使用.fir_transform一步生成即可

  • preprocessing.OneHotEncoder: 独热编码,创建哑变量
    把分类转换成数字的时候,忽略了数字中自带的数学性质,所以给算法传达了一些不准确的信息,而这会影响我们的建模。
    独热编码one-hot: 将特征转换为哑变量
    独热编码
    1
    2
    3
    4
    5
    from sklearn.preprocessing import OneHotEncoder
    X = data.iloc[:,1:-1]
    enc = OneHotEncoder(categories='auto').fit(X)
    result = enc.transform(X).toarray()
    # OneHotEncoder(categories='auto').fit_transform(X).toarray()

编码与哑变量

处理连续型特征:二值化与分段
  • sklearn.preprocessing.Binarizer
    根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0时,特征中所有的正值都映射到1。
    1
    2
    3
    from sklearn.preprocessing import Binarizer
    X = data.iloc[:,0].values.reshape(-1,1) #类为特征专用,所以不能使用一维数组
    transformer = Binarizer(threshold=30).fit_transform(X) # 大于30的全部变成1