sklearn_数据预处理和特征工程

转载自:菜菜的sklearn课堂

文章目录

  • 1 概述
    • 1.1 数据预处理与特征工程
    • 1.2 sklearn中的数据预处理和特征工程
  • 2 数据预处理 Preprocessing & Impute
    • 2.1 数据无量纲化
      • (1)数据归一化
      • (2)数据标准化
    • 2.2 缺失值
    • 2.3 处理分类型特征:编码与哑变量
      • 2.3.1 编码
        • (1)处理标签——分类标签==>分类数值
        • (2)处理特征——分类特征==>分类数值
      • 2.3.2 独热编码,创建哑变量
      • 2.3.3 序号编码
      • 2.3.4 二进制编码
    • 2.4 处理连续型特征:二值化与分段
      • 2.4.1 二值化——根据阈值将数据分为2半
      • 2.4.2 分段——根据数据的值进行分箱
    • 3 数据噪声
  • 3 特征选择 feature_selection
    • 3.1 Filter过滤法
      • 3.1.1 方差过滤
        • 3.1.1.1 VarianceThreshold
        • 3.1.1.2 方差过滤对模型的影响
      • 3.1.2 相关性过滤
        • 3.1.2.1 卡方过滤
          • 3.1.2.2 选取超参数K
        • 3.1.2.3 F检验
        • 3.1.2.4 互信息法
    • 3.2 Embedded嵌入法
    • 3.3 Wrapper包装法
    • 3.4 特征选择总结
  • 4 补充
    • 4.1 单变量特征选择SelectKBest
    • 4.2 递归特征消除RFE
    • 4.3 主成分分析PCA
    • 4.4 用极端决策树选择特征重要性
  • 5 特征工程——重要补充
    • 5.1 数值特征
  • 5.2 类别特征

使用sklearn做单机特征工程

1 概述

sklearn_数据预处理和特征工程_第1张图片
sklearn_数据预处理和特征工程_第2张图片sklearn_数据预处理和特征工程_第3张图片

1.1 数据预处理与特征工程

数据不给力,再高级的算法都没有用。

现实中的数据…

数据挖掘的五大流程:

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

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

  • 模块preprocessing:几乎包含数据预处理的所有内容
  • 模块Impute:填补缺失值专用 (在随机森林已经用过,用0、均值、随机森林回归填充)
  • 模块feature_selection:包含特征选择的各种方法的实践
  • 模块decomposition:包含降维算法

2 数据预处理 Preprocessing & Impute

sklearn_数据预处理和特征工程_第4张图片

2.1 数据无量纲化

sklearn_数据预处理和特征工程_第5张图片
图片来自:数据无量纲化处理(归一化VS标准化)

(1)数据归一化

若所用指标的值越大越好(正向指标:)
x i j ′ = x j − x min ⁡ x max ⁡ − x min ⁡ x'_{ij}=\frac{x_j-x_{\min}}{x_{\max}-x_{\min}} xij=xmaxxminxjxmin
若所用指标的值越小越好(逆向指标:)
x i j ′ = x max ⁡ − x j x max ⁡ − x min ⁡ x'_{ij}=\frac{x_{\max}-x_j}{x_{\max}-x_{\min}} xij=xmaxxminxmaxxj
在sklearn当中,使用 preprocessing.MinMaxScaler 来实现这个功能。MinMaxScaler有一个重要参数,feature_range,控制数据压缩到的范围,默认是[0,1]。

from sklearn.preprocessing import MinMaxScaler

data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
import pandas as pd
pd.DataFrame(data)
'''
     0   1
0 -1.0   2
1 -0.5   6
2  0.0  10
3  1.0  18
'''

'''
第一列 最大值 1 最小值-1
归一化 
data[0,0] = -1-(-1)/[1-(-1)] =0
data[1,0] = -0.5-(-1)/2 = 0.25
data[2,0] = 1/2 = 0.5
data[3,0] = 2/2 = 1

'''

#实现归一化
scaler = MinMaxScaler() #实例化
scaler = scaler.fit(data) #fit,在这里本质是生成min(x)和max(x)
result = scaler.transform(data) #通过接口导出结果
result
'''
array([[0.  , 0.  ],
       [0.25, 0.25],
       [0.5 , 0.5 ],
       [1.  , 1.  ]])
'''

result_ = scaler.fit_transform(data) #训练和导出结果一步达成
result_


scaler.inverse_transform(result) #将归一化后的结果逆转 还原
'''
array([[-1. ,  2. ],
       [-0.5,  6. ],
       [ 0. , 10. ],
       [ 1. , 18. ]])
'''


#使用MinMaxScaler的参数feature_range实现将数据归一化到[0,1]以外的范围中
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = MinMaxScaler(feature_range=[5,10]) #依然实例化
result = scaler.fit_transform(data) #fit_transform一步导出结果
result
'''
array([[ 5.  ,  5.  ],
       [ 6.25,  6.25],
       [ 7.5 ,  7.5 ],
       [10.  , 10.  ]])
'''

当X中的特征数量非常多的时候,fit会报错并表示,数据量太大了我计算不了,此时使用partial_fit作为训练接口

#scaler = scaler.partial_fit(data)

当然,也可以根据数学公式,编写程序计算

import numpy as np
X = np.array([[-1, 2], [-0.5, 6], [0, 10], [1, 18]])
#归一化
# 正向指标
X_nor = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_nor

# 负向指标
X_neg = (X.max(axis=0)- X) / (X.max(axis=0) - X.min(axis=0))
X_neg

#逆转归一化  还原
X_returned = X_nor * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0)
X_returned

补充:

在实际应用中,通过梯度下降法求解的模型通常是需要归一化的,包括线性回归、逻辑回归、支持向量机、神经网络等模型。但对于决策树模型则并不适用,以C4.5为例,决策树在进行节点分裂时主要依据数据集D关于特征x的信息增益比,而信息增益比跟特征是否经过归一化是无关的,因为归一化并不会改变样本在特征x上的信息增益。
引用自《百面机器学习》

(2)数据标准化

数据就会服从为均值为0,方差为1的正态分布(即标准正态分布)

x ∗ = x − μ σ x^*=\frac{x-\mu}{\sigma} x=σxμ

from sklearn.preprocessing import StandardScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]


scaler = StandardScaler() #实例化
scaler.fit(data) #fit,本质是生成均值和方差

scaler.mean_ #查看均值的属性mean_
scaler.var_ #查看方差的属性var_

x_std = scaler.transform(data) #通过接口导出结果
'''
array([[-1.18321596, -1.18321596],
       [-0.50709255, -0.50709255],
       [ 0.16903085,  0.16903085],
       [ 1.52127766,  1.52127766]])
'''

x_std.mean() #导出的结果是一个数组,用mean()查看均值
# 0.0
x_std.std() #用std()查看方差
# 1.0

scaler.fit_transform(data) #使用fit_transform(data)一步达成结果

scaler.inverse_transform(x_std) #使用inverse_transform逆转标准化

对于StandardScaler和MinMaxScaler来说,空值NaN会被当做是缺失值,在fit的时候忽略,在transform的时候保持缺失NaN的状态显示。

标准化 和 归一化 选哪个?

看情况。大多数机器学习算法中,会选择标准化来进行特征缩放,因为归一化对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,标准化往往是最好的选择。

归一化在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用归一化将数据压缩于[0,1]区间之中。

建议先试试看标准化,效果不好换归一化

2.2 缺失值

在sklearn当中,使用 impute.SimpleImputerr 来处理 缺失值

sklearn.impute.SimpleImputer (
missing_values=nan, 
strategy=’mean’, 
fill_value=None, 
verbose=0,
copy=True)

sklearn_数据预处理和特征工程_第6张图片

import pandas as pd
data = pd.read_csv(r"C:\Narrativedata.csv",index_col=0)
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
'''
data.info()
'''

Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Age       714 non-null    float64
 1   Sex       891 non-null    object 
 2   Embarked  889 non-null    object 
 3   Survived  891 non-null    object 
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''
#填补年龄
Age = data.loc[:,"Age"].values.reshape(-1,1) #sklearn当中特征矩阵必须是二维


from sklearn.impute import SimpleImputer

imp_mean = SimpleImputer() #实例化,默认均值填补
imp_median = SimpleImputer(strategy="median") #用中位数填补
imp_0 = SimpleImputer(strategy="constant",fill_value=0) #用0填补

imp_mean = imp_mean.fit_transform(Age) #fit_transform一步完成调取结果
imp_median = imp_median.fit_transform(Age)
imp_0 = imp_0.fit_transform(Age)

imp_mean[:20]
imp_median[:20]
imp_0[:20]

#在这里我们使用中位数填补Age
data.loc[:,"Age"] = imp_median
data.info()
'''

Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Age       891 non-null    float64
 1   Sex       891 non-null    object 
 2   Embarked  889 non-null    object 
 3   Survived  891 non-null    object 
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''

#使用众数填补Embarked
Embarked = data.loc[:,"Embarked"].values.reshape(-1,1) # 把有缺失的列取出,sklearn当中特征矩阵必须是二维
imp_mode = SimpleImputer(strategy = "most_frequent")
data.loc[:,"Embarked"] = imp_mode.fit_transform(Embarked)
data.info()
'''

Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Age       891 non-null    float64
 1   Sex       891 non-null    object 
 2   Embarked  891 non-null    object 
 3   Survived  891 non-null    object 
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''

用Pandas和Numpy进行填补其实更加简单

import pandas as pd
data = pd.read_csv(r"C:\Narrativedata.csv",index_col=0)
data.info()
'''

Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Age       714 non-null    float64
 1   Sex       891 non-null    object 
 2   Embarked  889 non-null    object 
 3   Survived  891 non-null    object 
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''

# 用中位数填充
data.loc[:,"Age"] = data.loc[:,"Age"].fillna(data.loc[:,"Age"].median())
data.info()
'''

Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Age       891 non-null    float64
 1   Sex       891 non-null    object 
 2   Embarked  889 non-null    object 
 3   Survived  891 non-null    object 
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''

#.fillna 在DataFrame里面直接进行填补
data.dropna(axis=0,inplace=True)
#.dropna(axis=0)删除所有有缺失值的行,.dropna(axis=1)删除所有有缺失值的列
#参数inplace,为True表示在原数据集上进行修改,为False表示生成一个复制对象,不修改原数据,默认False

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

分类型型特征原始输入通常是字符串形式,除了决策树等少数模型能直接处理字符串形式的输入,对于逻辑回归、支持向量机等模型来说,分类型型特征必须经过处理转换成数值型特征才能正确工作。

2.3.1 编码

比如说,学历的取值可以是[“小学”,“初中”,“高中”,“大学”],付费方式可能包含[“支付宝”,“现金”,“微信”]等等

将文字型数据转换为数值型

(1)处理标签——分类标签==>分类数值

preprocessing.LabelEncoder:标签专用,能够将分类转换为分类数值

from sklearn.preprocessing import LabelEncoder
y = data.iloc[:,-1] #要输入的是标签,不是特征矩阵,所以允许一维
'''
0           No
1          Yes
2          Yes
3          Yes
4           No
    ...
886         No
887        Yes
888         No
889    Unknown
890         No
Name: Survived, Length: 891, dtype: object
'''
le = LabelEncoder() #实例化
le = le.fit(y) #导入数据
label = le.transform(y) # transform接口调取结果
label #查看获取的结果label
'''
array([0, 2, 2, 2, 0, 0, 0, 0, 2,...,2, 0, 1, 0])
'''


le.classes_ #属性.classes_查看标签中究竟有多少类别
'''
array(['No', 'Unknown', 'Yes'], dtype=object)
'''
data.iloc[:,-1] = label #让标签等于我们运行出来的结果
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
'''

le.fit_transform(y) #也可以直接fit_transform一步到位
le.inverse_transform(label) #使用inverse_transform可以逆转

等价

from sklearn.preprocessing import LabelEncoder
data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])

(2)处理特征——分类特征==>分类数值

preprocessing.OrdinalEncoder:特征专用,能够将分类特征转换为分类数值

from sklearn.preprocessing import OrdinalEncoder

data_ = data.copy()
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_.info()
'''

Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Age       891 non-null    float64
 1   Sex       891 non-null    object 
 2   Embarked  889 non-null    object 
 3   Survived  891 non-null    int32  
dtypes: float64(1), int32(1), object(2)
memory usage: 31.3+ KB
'''
# 先删除有缺失值的行
data_.dropna(axis=0,inplace=True)


# 处理 Sex 和  Embarked
OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
'''
 [array(['female', 'male'], dtype=object), array(['C', 'Q', 'S'], dtype=object)]
'''

data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
data_.head()
'''
    Age  Sex  Embarked  Survived
0  22.0  1.0       2.0         0
1  38.0  0.0       0.0         2
2  26.0  0.0       2.0         2
3  35.0  0.0       2.0         2
4  35.0  1.0       2.0         0
'''
OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
'''
[array([0., 1.]), array([0., 1., 2.])]
'''

Sex 和 Embarked 已经转换为 分类数值型

2.3.2 独热编码,创建哑变量

独热编码通常用于处理类别间不具有大小关系的特征。

三种不同性质的分类数据:

  • 舱门(S,C,Q)
    三种取值S,C,Q是相互独立的,彼此之间完全没有联系,表达的是S≠C≠Q的概念。这是名义变量
  • 学历(小学,初中,高中)
    三种取值不是完全独立的,我们可以明显看出,在性质上可以有高中>初中>小学这样的联系,学历有高低,但是学历取值之间却不是可以计算的,不能说小学 + 某个取值 = 初中。这是有序变量
  • 体重(>45kg,>90kg,>135kg)
    各个取值之间有联系,且是可以互相计算的,比如120kg - 45kg = 90kg,分类之间可以通过数学计算互相转换。这是有距变量

然而在对特征进行编码的时候,这三种分类数据都会被我们转换为 [ 0, 1, 2],这三个数字在算法看来,是连续且可以计算的,这三个数字相互不等,有大小,并且有着可以相加相乘的联系。所以算法会把舱门,学历这样的分类特征,都误会成是体重这样的分类特征。这是说,我们把分类转换成数字的时候,忽略了数字中自带的数学性质,所以给算法传达了一些不准确的信息,而这会影响我们的建模。

类别OrdinalEncoder可以用来处理有序变量,但对于名义变量,只有使用哑变量的方式来处理,才能够尽量向算法传达最准确的信息:
sklearn_数据预处理和特征工程_第7张图片

性别和舱门等这样的名义变量。需要使用独热编码,将两个特征都转换为哑变量

preprocessing.OneHotEncoder:独热编码,创建哑变量

from sklearn.preprocessing import OneHotEncoder

data_ = data.copy()
# 先删除有缺失值的行,才不会报错
data_.dropna(axis=0,inplace=True)
X = data_.iloc[:,1:-1]

enc = OneHotEncoder(categories='auto').fit(X)
result = enc.transform(X).toarray()
result
'''
--------------↓-------------
array([[0., 1., 0., 0., 1.],
       [1., 0., 1., 0., 0.],
       [1., 0., 0., 0., 1.],
       ...,
       [1., 0., 0., 0., 1.],
       [0., 1., 1., 0., 0.],
       [0., 1., 0., 1., 0.]])
'''
# OneHotEncoder(categories='auto').fit_transform(X).toarray()

# 还原
pd.DataFrame(enc.inverse_transform(result))


enc.get_feature_names()
'''
array(['x0_female', 'x0_male', 'x1_C', 'x1_Q', 'x1_S'], dtype=object)

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

第一列对应x0_female,第二列对应x0_male ...
'''

#左右合并data  result
newdata = pd.concat([data_,pd.DataFrame(result)],axis=1)
newdata.head()
'''
    Age     Sex Embarked  Survived    0    1    2    3    4
0  22.0    male        S         0  0.0  1.0  0.0  0.0  1.0
1  38.0  female        C         2  1.0  0.0  1.0  0.0  0.0
2  26.0  female        S         2  1.0  0.0  0.0  0.0  1.0
3  35.0  female        S         2  1.0  0.0  0.0  0.0  1.0
4  35.0    male        S         0  0.0  1.0  0.0  0.0  1.0
'''
# 删除原来的
newdata.drop(["Sex","Embarked"],axis=1,inplace=True)
'''
    Age  Survived    0    1    2    3    4
0  22.0       0.0  0.0  1.0  0.0  0.0  1.0
1  38.0       2.0  1.0  0.0  1.0  0.0  0.0
2  26.0       2.0  1.0  0.0  0.0  0.0  1.0
3  35.0       2.0  1.0  0.0  0.0  0.0  1.0
4  35.0       0.0  0.0  1.0  0.0  0.0  1.0
'''
newdata.columns =["Age","Survived","Female","Male","Embarked_C","Embarked_Q","Embarked_S"]
newdata.head()

'''
    Age  Survived  Female  Male  Embarked_C  Embarked_Q  Embarked_S
0  22.0       0.0     0.0   1.0         0.0         0.0         1.0
1  38.0       2.0     1.0   0.0         1.0         0.0         0.0
2  26.0       2.0     1.0   0.0         0.0         0.0         1.0
3  35.0       2.0     1.0   0.0         0.0         0.0         1.0
4  35.0       0.0     0.0   1.0         0.0         0.0         1.0
'''

sklearn_数据预处理和特征工程_第8张图片
数据类型以及常用的统计量
sklearn_数据预处理和特征工程_第9张图片

对于类别取值较多的情况下使用独热编码需要注意以下问题。

(1)使用稀疏向量来节省空间。在独热编码下,特征向量只有某一维取值为1,其他位置取值均为0。因此可以利用向量的稀疏表示有效地节省空间,并且目前大部分的算法均接受稀疏向量形式的输入。
(2)配合特征选择来降低维度。高维度特征会带来几方面的问题。
一是在K近邻算法中,高维空间下两点之间的距离很难得到有效的衡量;二是在逻辑回归模型中,参数的数量会随着维度的增高而增加,容易引起过拟合问题;三是通常只有部分维度是对分类、预测有帮助,因此可以考虑配合特征选择来降低维度。
引用《百面机器学习》

2.3.3 序号编码

引用《百面机器学习》

序号编码通常用于处理类别间具有大小关系的数据。例如成绩,可以分为低、中、高三档,并且存在“高>中>低”的排序关系。序号编码会按照大小关系对类别型特征赋予一个数值ID,例如高表示为3、中表示为2、低表示为1,转换后依然保留了大小关系。

2.3.4 二进制编码

二进制编码主要分为两步,先用序号编码给每个类别赋予一个类别ID,然后将类别ID对应的二进制编码作为结果。

二进制编码本质上是利用二进制对ID进行哈希映射,最终得到0/1特征向量,且维数少于独热编码,节省了存储空间。

sklearn_数据预处理和特征工程_第10张图片

2.4 处理连续型特征:二值化与分段

2.4.1 二值化——根据阈值将数据分为2半

  • sklearn.preprocessing.Binarizer

根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量

大于阈值的值映射为1,而小于或等于阈值的值映射为0。

默认阈值为0时,特征中所有的正值都映射到1。二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯设置中的伯努利分布建模)。

转换前

import pandas as pd
data = pd.read_csv(r"C:\Narrativedata.csv",index_col=0)
data.head()
data.info()
data_1 = data.copy()
data_1 = pd.DataFrame(data_1)
# 先删除有缺失值的行,才不会报错
data_1 = data_1.dropna(axis=0) 

data_1.reset_index(drop=True, inplace=True)


'''
      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
..    ...     ...      ...      ...
707  39.0  female        Q       No
708  27.0    male        S       No
709  19.0  female        S      Yes
710  26.0    male        C  Unknown
711  32.0    male        Q       No

[712 rows x 4 columns]
'''

转换后

#将年龄二值化
from sklearn.preprocessing import Binarizer
# 取出要二值化的特征——Age
X = data_1.iloc[:,0].values.reshape(-1,1) #类为特征专用,所以不能使用一维数组

# 小于或者等于30的为0,大于30的为1
transformer = Binarizer(threshold=30).fit_transform(X) # threshold=30为阈值
# 替换
data_1.iloc[:,0] = transformer
data_1
'''
     Age     Sex Embarked Survived
0    0.0    male        S       No
1    1.0  female        C      Yes
2    0.0  female        S      Yes
3    1.0  female        S      Yes
4    1.0    male        S       No
..   ...     ...      ...      ...
707  1.0  female        Q       No
708  0.0    male        S       No
709  0.0  female        S      Yes
710  0.0    male        C  Unknown
711  1.0    male        Q       No

[712 rows x 4 columns]
'''

2.4.2 分段——根据数据的值进行分箱

  • preprocessing.KBinsDiscretizer

这是将连续型变量划分为分类变量的类,能够将连续型变量排序后按顺序分箱后编码。总共包含三个重要参数:
sklearn_数据预处理和特征工程_第11张图片
分为3箱 等宽分箱 每个特征的每个箱都被编码为一个整数

from sklearn.preprocessing import KBinsDiscretizer
import pandas as pd
data = pd.read_csv(r"C:\Narrativedata.csv",index_col=0)
data.head()
data.info()
data_1 = data.copy()
data_1 = pd.DataFrame(data_1)
# 先删除有缺失值的行,才不会报错
data_1 = data_1.dropna(axis=0) 
data_1.reset_index(drop=True, inplace=True)
data_1
'''
      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
..    ...     ...      ...      ...
707  39.0  female        Q       No
708  27.0    male        S       No
709  19.0  female        S      Yes
710  26.0    male        C  Unknown
711  32.0    male        Q       No

[712 rows x 4 columns]
'''
#类为特征专用,所以不能使用一维数组
X = data_1.iloc[:,0].values.reshape(-1,1)
# 分为3箱 等宽分箱 每个特征的每个箱都被编码为一个整数
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
est = est.fit_transform(X)
# 替换
data_1.iloc[:,0] = est
data_1

'''
     Age     Sex Embarked Survived
0    0.0    male        S       No
1    1.0  female        C      Yes
2    0.0  female        S      Yes
3    1.0  female        S      Yes
4    1.0    male        S       No
..   ...     ...      ...      ...
707  1.0  female        Q       No
708  1.0    male        S       No
709  0.0  female        S      Yes
710  0.0    male        C  Unknown
711  1.0    male        Q       No

[712 rows x 4 columns]
'''
#查看转换后分的箱:变成了一列中的三箱
set(data_1.iloc[:,0])  # {0.0, 1.0, 2.0}

分为3箱 等宽分箱 独热编码

est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform')
#查看转换后分的箱:变成了哑变量
est.fit_transform(X).toarray()
'''
array([[1., 0., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       ...,
       [1., 0., 0.],
       [1., 0., 0.],
       [0., 1., 0.]])
'''

3 数据噪声

参考:《美团机器学习实战》
sklearn_数据预处理和特征工程_第12张图片
sklearn_数据预处理和特征工程_第13张图片
sklearn_数据预处理和特征工程_第14张图片
这里提到,对于带噪声的特征数据,去掉后效果可能反而不好,因此,我们在进行数据去噪时,应该分清楚哪些噪声可以去除或者必须去除,哪些又该保留。

除此之外,还提到,数据过滤方法有一个过滤曝光无效数据,或者过滤大部分曝光无效数据,保留少数未曝光数据,如上图。

3 特征选择 feature_selection

引用机器学习python实战
特征选择是一个流程,能够选择有助于提高预测结果准确度的特征数据,或者有助于发现我们感兴趣的输出结果的特征数据。如果数据中包含无关的特征属性,会降低算法的准确度,对预测新数据造成干扰,尤其是线性相关算法(如线性回归算法和逻辑回归算法)。因此,在开始建立模型之前,执行特征选定有助于:

  • 降低数据的拟合度:较少的冗余数据,会使算法得出结论的机会更大。
  • 提高算法精度:较少的误导数据,能够提高算法的准确度。
  • 减少训练时间:越少的数据,训练模型所需要的时间越少。

sklearn_数据预处理和特征工程_第15张图片
sklearn_数据预处理和特征工程_第16张图片
当数据预处理完成后,我们就要开始进行特征工程了。

sklearn_数据预处理和特征工程_第17张图片

开始之前

是理解业务和数据含义,根据我们的目标,用业务常识来选择特征

确定判断目的,辨别无关特征,判断相关性比较低的特征、相关性比较高的特征

所以,特征工程的第一步是:理解业务。

若无法依赖对业务的理解来选择特征,有四种方法可以用来选择特征:过滤法,嵌入法,包装法,和降维算法。


准备数据

import pandas as pd
data = pd.read_csv(r"C:\digit recognizor.csv")
data.head()
'''
   label  pixel0  pixel1  pixel2  ...  pixel780  pixel781  pixel782  pixel783
0      1       0       0       0  ...         0         0         0         0
1      0       0       0       0  ...         0         0         0         0
2      1       0       0       0  ...         0         0         0         0
3      4       0       0       0  ...         0         0         0         0
4      0       0       0       0  ...         0         0         0         0

[5 rows x 785 columns]
'''
# 有785个特征

X = data.iloc[:,1:] # 特征
y = data.iloc[:,0] # 标签
X.shape # (42000, 784)

3.1 Filter过滤法

过滤方法通常用作预处理步骤,特征选择完全独立于任何机器学习算法。它是根据各种统计检验中的分数以及相关性的各项指标来选择特征。
在这里插入图片描述

3.1.1 方差过滤

3.1.1.1 VarianceThreshold

这是通过特征本身的方差来筛选特征的类

比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。所以无论接下来的特征工程要做什么,都要优先消除方差为0的特征

VarianceThreshold有重要参数threshold,表示方差的阈值,表示舍弃所有方差小于threshold的特征,不填默认为0,即删除所有的记录都相同的特征。

from sklearn.feature_selection import VarianceThreshold

selector = VarianceThreshold() #实例化,不填参数默认方差为0
X_var0 = selector.fit_transform(X) #获取删除不合格特征之后的新特征矩阵
#也可以直接写成 X = VairanceThreshold().fit_transform(X)
X_var0.shape

(42000, 708)

若要删除一般的特征,可以用特征方差的中位数作为参数 threshold 的值

import numpy as np
# 特征方差中位数
yuzhi = np.median(X.var().values) # 1352.286703180131

X_fsvar = VarianceThreshold(yuzhi).fit_transform(X)
X_fsvar.shape

(42000, 392)
# 当特征是二分类时,特征的取值就是伯努利随机变量
#若特征是伯努利随机变量,假设p=0.8,即二分类特征中某种分类占到80%以上的时候删除特征
X_bvar = VarianceThreshold(.8 * (1 - .8)).fit_transform(X)
X_bvar.shape

3.1.1.2 方差过滤对模型的影响

方差过滤这样做了以后,对模型效果会有怎样的影响呢?

KNN vs 随机森林在不同方差过滤效果下的对比

from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.neighbors import KNeighborsClassifier as KNN
from sklearn.model_selection import cross_val_score
import numpy as np

X = data.iloc[:,1:] # 特征
y = data.iloc[:,0]  # 标签
# 方差中位数过滤
X_fsvar = VarianceThreshold(np.median(X.var().values)).fit_transform(X)

KNN方差过滤前

cross_val_score(KNN(),X,y,cv=5).mean()  # 0.9658569780264943

KNN方差过滤后

cross_val_score(KNN(),X_fsvar,y,cv=5).mean() # 0.9659997478150573

对于KNN,过滤后的效果十分明显:准确率稍有提升


随机森林方差过滤前

cross_val_score(RFC(n_estimators=10,random_state=0),X,y,cv=5).mean() # e.9380003861799541

随机森林方差过滤后

cross_val_score(RFC(n_estimators=10,random_state=0),X_fsvar,y,cv=5).mean() # e.9388098166696807

最近邻算法KNN,单棵决策树,支持向量机SVM,神经网络,回归算法,都需要遍历特征或升维来进行运算,所以他们本身的运算量就很大,需要的时间就很长,因此方差过滤这样的特征选择对他们来说就尤为重要。

过滤法的主要对象是:需要遍历特征或升维的算法

过滤法的主要目的是:在维持算法表现的前提下,帮助算法们降低计算成本。

对于不需要遍历特征的算法,比如随机森林,它随机选取特征进行分枝,本身运算就非常快速,因此特征选择对它来说效果平平

过滤法对随机森林无效,却对树模型有效?
从算法原理上来说,传统决策树需要遍历所有特征,计算不纯度后进行分枝,而随机森林却是随机选择特征进行计算和分枝,因此随机森林的运算更快,过滤法对随机森林无用,对决策树却有用

在sklearn中,决策树和随机森林都是随机选择特征进行分枝,但决策树在建模过程中随机抽取的特征数目却远远超过随机森林当中每棵树随机抽取的特征数目(比如说对于这个780维的数据,随机森林每棵树只会抽取10~20个特征,而决策树可能会抽取300~400个特征),因此,过滤法对随机森林无用,却对决策树有用

也因此,在sklearn中,随机森林中的每棵树都比单独的一棵决策树简单得多,高维数据下的随机森林的计算比决策树快很多。
sklearn_数据预处理和特征工程_第18张图片

如果过滤之后模型的效果反而变差了,我们就可以认为,被我们过滤掉的特征中有很多都有有效特征,那我们就放弃过滤,使用其他手段来进行特征选择。

现实中,一般只会使用阈值为0或者阈值很小的方差过滤,来优先消除一些明显用不到的特征,然后再选择更优的特征选择方法继续削减特征数量。

3.1.2 相关性过滤

方差挑选完毕之后,要考虑下一个问题:相关性了。我们希望选出与标签相关且有意义的特征,因为这样的特征能够为我们提供大量信息。

评判特征与标签之间的相关性:卡方,F检验,互信息

3.1.2.1 卡方过滤

卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类feature_selection.chi2 计算每个非负特征标签之间的卡方统计量,并依照卡方统计量由高到低为特征排名。再结合 feature_selection.SelectKBest 这个可以输入”评分标准“来选出前K个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。

如果卡方检验检测到某个特征中所有的值都相同,会提示我们使用方差先进行方差过滤。

from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#假设在这里我一直我需要300个特征
X_fschi = SelectKBest(chi2, k=300).fit_transform(X_fsvar, y)
X_fschi.shape # (42000, 392)

使用threshold=中位数时完成的方差过滤的数据来做卡方检验

from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#假设在这里我一直我需要300个特征
X_fschi = SelectKBest(chi2, k=300).fit_transform(X_fsvar, y)
X_fschi.shape #  (42000, 300)

# 验证一下模型的效果如何:
cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()

# 0.9344761904761905
3.1.2.2 选取超参数K

如何设置一个最佳的K值?

(1)学习曲线

import matplotlib.pyplot as plt
score = []
for i in range(390,200,-10):
    X_fschi = SelectKBest(chi2, k=i).fit_transform(X_fsvar, y)
    once = cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()
    score.append(once)
plt.plot(range(350,200,-10),score)
plt.show()

(2)p值选择k

卡方检验的本质是推测两组数据之间的差异,其检验的原假设是”两组数据是相互独立的”。

p值小于0.05的特征,即和标签是相关联的特征。

chivalue, pvalues_chi = chi2(X_fsvar,y)
chivalue
pvalues_chi
#k取多少?我们想要消除所有p值大于设定值,比如0.05或0.01的特征:
k = chivalue.shape[0] - (pvalues_chi > 0.05).sum()
X_fschi = SelectKBest(chi2, k).fit_transform(X_fsvar, y)
cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()

若所有特征的p值都是0,说明对于这个数据集来说,方差验证已经把所有和标签无关的特征都剔除了,或者这个数据集本身就不含与标签无关的特征。在这种情况下,舍弃任何一个特征,都会舍弃对模型有用的信息,而使模型表现下降。

3.1.2.3 F检验

F检验,又称ANOVA(方差分析),方差齐性检验,是用来捕捉每个特征与标签之间的线性关系的过滤方法。它即可以做回归也可以做分类,因此包含feature_selection.f_classif(F检验分类)和feature_selection.f_regression(F检验回归)两个类。其中F检验分类用于标签是离散型变量的数据,而F检验回归用于标签是连续型变量的数据。

F检验在数据服从正态分布时效果会非常稳定,因此如果使用F检验过滤,会先将数据转换成服从正态分布的方式。

F检验的本质是寻找两组数据之间的线性关系

选取p值小于0.05或0.01的特征,这些特征与标签时显著线性相关的

from sklearn.feature_selection import f_classif
F, pvalues_f = f_classif(X_fsvar,y)
F
pvalues_f
k = F.shape[0] - (pvalues_f > 0.05).sum()
X_fsF = SelectKBest(f_classif, k).fit_transform(X_fsvar, y)
cross_val_score(RFC(n_estimators=10,random_state=0),X_fsF,y,cv=5).mean()

3.1.2.4 互信息法

互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性非线性关系)的过滤方法。

和F检验相似,它既可以做回归也可以做分类,并且包含两个类feature_selection.mutual_info_classif(互信息分类)和
feature_selection.mutual_info_regression(互信息回归)。

互信息法比F检验更加强大,F检验只能够找出线性关系,而互信息法可以找出任意关系。

互信息法不返回p值或F值类似的统计量,它返回“每个特征与目标之间的互信息量的估计”,这个估计量在[0,1]之间取值,为0则表示两个变量独立,为1则表示两个变量完全相关。

from sklearn.feature_selection import mutual_info_classif as MIC
result = MIC(X_fsvar,y)
k = result.shape[0] - sum(result <= 0)
X_fsmic = SelectKBest(MIC, k).fit_transform(X_fsvar, y)
cross_val_score(RFC(n_estimators=10,random_state=0),X_fsmic,y,cv=5).mean()

过滤法总结

可以先使用方差过滤,然后使用互信息法来捕捉相关性
sklearn_数据预处理和特征工程_第19张图片

3.2 Embedded嵌入法

嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同时进行。在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。这些权值系数往往代表了特征对于模型的某种贡献或某种重要性,找出对模型建立最有用的特征。
sklearn_数据预处理和特征工程_第20张图片

因此相比于过滤法嵌入法的结果会更加精确到模型的效用本身,对于提高模型效力有更好的效果。并且,由于考虑特征对模型的贡献,因此无关的特征(需要相关性过滤的特征)和无区分度的特征(需要方差过滤的特征)都会因为缺乏对模型的贡献而被删除掉,可谓是过滤法的进化版

sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefit=False, norm_order=1,max_features=None)

sklearn_数据预处理和特征工程_第21张图片
SelectFromModel是一个元变换器,可以与任何在拟合后具有coef_,feature_importances_属性或参数中可选惩罚项的评估器一起使用

对于有feature_importances_的模型来说,若重要性低于提供的阈值参数,则认为这些特征不重要并被移除。feature_importances_的取值范围是[0,1],如果设置阈值很小,比如0.001,就可以删除那些对标签预测完全没贡献的特征。如果设置得很接近1,可能只有一两个特征能够被留下。

使用随机森林为例,则需要学习曲线来帮助我们寻找最佳特征值。

# 导包
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier as RFC
# 建模
# 实例化
RFC_ = RFC(n_estimators =10,random_state=0)

# threshold 阈值
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y)
#在这里我只想取出来有限的特征。0.005这个阈值对于有780个特征的数据来说,是非常高的阈值,因为平均每个特征
#只能够分到大约0.001的feature_importances_

X_embedded.shape # (42000, 47)

#模型的维度明显被降低了
#同样的,我们也可以画学习曲线来找最佳阈值

import numpy as np
import matplotlib.pyplot as plt
RFC_.fit(X,y).feature_importances_
threshold = np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20)
score = []
for i in threshold:
    X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
    once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
    score.append(once)
plt.plot(threshold,score)
plt.show()

在嵌入法下,很容易就能够实现特征选择的目标:减少计算量,提升模型表现。

因此,比起要思考很多统计量的过滤法来说,嵌入法可能是更有效的一种方法。然而,在算法本身很复杂的时候,过滤法的计算远远比嵌入法要快,所以大型数据中,我们还是会优先考虑过滤法。

3.3 Wrapper包装法

包装法也是一个特征选择和算法训练同时进行的方法,与嵌入法十分相似,它也是依赖于算法自身的选择,比如coef_属性或feature_importances_属性来完成特征选择。

往往使用一个目标函数作为黑盒来帮助我们选取特征,而不是自己输入某个评估指标或统计量的阈值。包装法在初始特征集上训练评估器,并且通过coef_属性或通过feature_importances_属性获得每个特征的重要性。然后,从当前的一组特征中修剪最不重要的特征。在修剪的集合上递归地重复该过程,直到最终到达所需数量的要选择的特征。
sklearn_数据预处理和特征工程_第22张图片
图中的“算法”,指的不是我们最终用来导入数据的分类或回归算法(即不是随机森林),而是专业的数据挖掘算法,即我们的目标函数。这些数据挖掘算法的核心功能就是选取最佳特征子集。

最典型的目标函数是递归特征消除法,是一种贪婪的优化算法,旨在找到性能最佳的特征子集。

包装法的效果是所有特征选择方法中最利于提升模型表现的,它可以使用很少的特征达到很优秀的效果。

包装法是最能保证模型效果的特征选择方法。不适用于太大型的数据

sklearn.feature_selection.RFE (estimator, n_features_to_select=None, step=1, verbose=0)

参数
estimator是需要填写的实例化后的评估器,
n_features_to_select是想要选择的特征个数,
step 表示每次迭代中希望移除的特征个数。

除此之外,RFE类有两个很重要的属性,
.support_:返回所有的特征的是否最后被选中的布尔矩阵,
.ranking_返回特征的按数次迭代中综合重要性的排名。

类feature_selection.RFECV会在交叉验证循环中执行RFE以找到最佳数量的特征,增加参数cv,其他用法都和RFE一模一样。

from sklearn.feature_selection import RFE
RFC_ = RFC(n_estimators =10,random_state=0)
selector = RFE(RFC_, n_features_to_select=340, step=50).fit(X, y)
selector.support_.sum() # .support_返回所有的特征的是否最后被选中的布尔矩阵
selector.ranking_  # 返回特征的按数次迭代中综合重要性的排名
X_wrapper = selector.transform(X)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()

3.4 特征选择总结

经验来说,
过滤法更快速,但更粗糙。

包装法嵌入法更精确,比较适合具体到算法去调整,但计算量比较大,运行时间长。

当数据量很大的时候,优先使用方差过滤和互信息法调整,再上其他特征选择方法。使用逻辑回归时,优先使用嵌入法。使用支持向量机时,优先使用包装法。迷茫的时候,从过滤法走起,看具体数据具体分析。

特征选择只是特征工程中的第一步。真正的高手,往往使用特征创造或特征提取来寻找高级特征。


引用:《数据竞赛入门》

在做数据竞赛的过程中,过滤式选择一般用在初期进行特征筛选,比如从原始数据集中筛选合适的特征子集;包裹式选择一般和模型的训练一起进行,通过模型的性能来筛选特征;嵌入式选择一般用于模型训练后进行特征筛选

需要注意的是特性筛选具有一定的随机性,搜索空间非常大,所以并没有一个完美的解决方案。在做比赛过程中,验证特征是否有效的方式是包裹式选择,因为模型精度最终的目标,同时包裹式选择的流程可以根据模型来筛选特征,这也是我们需要的。

在任何时候都应该优先相信模型交叉验证的精度。
在这里插入图片描述

4 补充

这里补充:《机器学习python实战》

实际上,前面已经做过,可学习前面的

4.1 单变量特征选择SelectKBest

统计分析可以用来分析选择对结果影响最大的数据特征。在scikit-learn中提供了SelectKBest类,可以使用一系列统计方法来选定数据特征,是对卡方检验的实现。

import os
os.getcwd() # 查看当前工作目录
os.chdir(r"F:\MachineLearning-master\MachineLearning-master\chapter09") # 改变目录,注意双引号和反斜杠

# 通过卡方检验选定数据特征
from pandas import read_csv
from numpy import set_printoptions
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
# 导入数据
filename = 'pima_data.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
data = read_csv(filename, names=names)
# 将数据分为输入数据和输出结果
array = data.values
X = array[:, 0:8]
Y = array[:, 8]
'''
array([[  6.   , 148.   ,  72.   , ...,  33.6  ,   0.627,  50.   ],
       [  1.   ,  85.   ,  66.   , ...,  26.6  ,   0.351,  31.   ],
       [  8.   , 183.   ,  64.   , ...,  23.3  ,   0.672,  32.   ],
       ...,
       [  5.   , 121.   ,  72.   , ...,  26.2  ,   0.245,  30.   ],
       [  1.   , 126.   ,  60.   , ...,  30.1  ,   0.349,  47.   ],
       [  1.   ,  93.   ,  70.   , ...,  30.4  ,   0.315,  23.   ]])
'''
# 特征选定
test = SelectKBest(score_func=chi2, k=4)
fit = test.fit(X, Y)
set_printoptions(precision=3)
print(fit.scores_)
features = fit.transform(X)
print(features)
'''
[[148.    0.   33.6  50. ]
 [ 85.    0.   26.6  31. ]
 [183.    0.   23.3  32. ]
 ...
 [121.  112.   26.2  30. ]
 [126.    0.   30.1  47. ]
 [ 93.    0.   30.4  23. ]]
'''

4.2 递归特征消除RFE

递归特征消除(RFE)使用一个基模型来进行多轮训练,每轮训练后消除若干权值系数的特征,再基于新的特征集进行下一轮训练。通过每一个基模型的精度,找到对最终的预测结果影响最大的数据特征。

在scikit-learn文档中有更多的关于递归特征消除(RFE)的描述。

下面的例子是以逻辑回归算法为基模型,通过递归特征消除来选定对预测结果影响最大的三个数据特征。代码如下:

import os
os.getcwd() # 查看当前工作目录
os.chdir(r"F:\MachineLearning-master\MachineLearning-master\chapter09") # 改变目录,注意双引号和反斜杠

# 通过递归消除来选定特征
from pandas import read_csv
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
# 导入数据
filename = 'pima_data.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
data = read_csv(filename, names=names)
# 将数据分为输入数据和输出结果
array = data.values
X = array[:, 0:8]
Y = array[:, 8]

'''
array([[  6.   , 148.   ,  72.   , ...,  33.6  ,   0.627,  50.   ],
       [  1.   ,  85.   ,  66.   , ...,  26.6  ,   0.351,  31.   ],
       [  8.   , 183.   ,  64.   , ...,  23.3  ,   0.672,  32.   ],
       ...,
       [  5.   , 121.   ,  72.   , ...,  26.2  ,   0.245,  30.   ],
       [  1.   , 126.   ,  60.   , ...,  30.1  ,   0.349,  47.   ],
       [  1.   ,  93.   ,  70.   , ...,  30.4  ,   0.315,  23.   ]])
'''
# 特征选定
model = LogisticRegression()
rfe = RFE(model, 3)
fit = rfe.fit(X, Y)
print("特征个数:")
print(fit.n_features_) # 3
print("被选定的特征:") # [ True False False False False  True  True False]
print(fit.support_)
print("特征排名:")
print(fit.ranking_) # [1 2 4 5 6 1 1 3]

RFE选定了preg、mass和pedi三个数据特征,它们在support_中被标记为True,在ranking_中被标记为1。

4.3 主成分分析PCA

import os
os.getcwd() # 查看当前工作目录
os.chdir(r"F:\MachineLearning-master\MachineLearning-master\chapter09") # 改变目录,注意双引号和反斜杠

# 通过主要成分分析选定数据特征
from pandas import read_csv
from sklearn.decomposition import PCA
# 导入数据
filename = 'pima_data.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
data = read_csv(filename, names=names)
# 将数据分为输入数据和输出结果
array = data.values
X = array[:, 0:8]

'''
array([[  6.   , 148.   ,  72.   , ...,  33.6  ,   0.627,  50.   ],
       [  1.   ,  85.   ,  66.   , ...,  26.6  ,   0.351,  31.   ],
       [  8.   , 183.   ,  64.   , ...,  23.3  ,   0.672,  32.   ],
       ...,
       [  5.   , 121.   ,  72.   , ...,  26.2  ,   0.245,  30.   ],
       [  1.   , 126.   ,  60.   , ...,  30.1  ,   0.349,  47.   ],
       [  1.   ,  93.   ,  70.   , ...,  30.4  ,   0.315,  23.   ]])
'''
Y = array[:, 8]
# 特征选定
pca = PCA(n_components=3)
fit = pca.fit(X)
print("解释方差:%s" % fit.explained_variance_ratio_)  # 解释方差:[0.889 0.062 0.026]
print(fit.components_)
'''
[[-2.022e-03  9.781e-02  1.609e-02  6.076e-02  9.931e-01  1.401e-02
   5.372e-04 -3.565e-03]
 [-2.265e-02 -9.722e-01 -1.419e-01  5.786e-02  9.463e-02 -4.697e-02
  -8.168e-04 -1.402e-01]
 [-2.246e-02  1.434e-01 -9.225e-01 -3.070e-01  2.098e-02 -1.324e-01
  -6.400e-04 -1.255e-01]]
'''

4.4 用极端决策树选择特征重要性

袋装决策树算法(Bagged Decision Tress)、随机森林算法和极端随机树算法都可以用来计算数据特征的重要性。

import os
os.getcwd() # 查看当前工作目录
os.chdir(r"F:\MachineLearning-master\MachineLearning-master\chapter09") # 改变目录,注意双引号和反斜杠

# 通过决策树计算特征的重要性
from pandas import read_csv
from sklearn.ensemble import ExtraTreesClassifier
# 导入数据
filename = 'pima_data.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
data = read_csv(filename, names=names)
# 将数据分为输入数据和输出结果
array = data.values
X = array[:, 0:8]
Y = array[:, 8]
# 特征选定
model = ExtraTreesClassifier()
fit = model.fit(X, Y)
print(fit.feature_importances_) # [0.111 0.237 0.1   0.079 0.074 0.136 0.116 0.146]

lst_dict = dict(zip(names,[0.111 ,0.237 ,0.1 ,  0.079 ,0.074, 0.136, 0.116, 0.146]))
print(lst_dict)

# {'preg': 0.111, 'plas': 0.237, 'pres': 0.1, 'skin': 0.079, 'test': 0.074, 'mass': 0.136, 'pedi': 0.116, 'age': 0.146}

5 特征工程——重要补充

参考:《美团机器学习实战》

5.1 数值特征

sklearn_数据预处理和特征工程_第23张图片
数值特征的处理方法

5.2 类别特征

你可能感兴趣的:(机器学习)