sklearn学习——特征工程(特征选择)

特征选择方法总结

什么是特征工程?

定义:特征工程是将原始数据转化为特征,更好表示预测模型处理的实际问题,提升对于未知数据的准确性。它是用目标问题所在的特定领域知识或者自动化的方法来生成、提取、删减或者组合变化得到特征。

为什么要特征工程?

简单的说,你给我的数据能不能直接放到模型里?显然不能,第一,你的数据可能是假(异常值); 第二,你的数据太脏了(各种噪声);第三,你的数据可能不够,或者数据量不平衡(数据采样);第三,清洗完数据能直接用吗?显然不能!输入模型的数据要和模型输出有关系,没关系的那是噪声!(特征提取或处理);第四,特征之间属于亲戚关系,你们是一家,不能反映问题!(特征选择)。

特征工程有何意义?

这里用七月在线寒老师的PPT做解释:
这里写图片描述
这里写图片描述

如何特征进行工程?

这里写图片描述


本文重点叙述特征选择(Feature selection)

sklearn.feature_selection
有别于降维算法(PCA, SVD)

方法一:过滤型(Fillter)

评估单个特征和结果值之间的相关程度,排序留下Top相关的特征部分。

Person相关系数法:
import numpy as np
from scipy.stats import pearsonr#引入数值计算包的统计函数(scipy.stats)
np.random.seed(0)#保证每次随机取值相同
size = 300
x = np.random.normal(0, 1, size)#正态分布
print ("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print ("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))

Person相关系数的缺点: 作为特征排序机制,他只对线性关系敏感。如果关系是非线性的,即便两个变量具有一一对应的关系,Pearson相关性也可能会接近0。

x = np.random.uniform(-1, 1, 100000)
print pearsonr(x, x**2)[0]
互信息和最大信息系数 Mutual information and maximal information coefficient (MIC)

这里写图片描述

import numpy as np
from minepy import MINE#minepy包——基于最大信息的非参数估计
m = MINE()
x = np.random.uniform(-1, 1, 10000)#均匀分布
m.compute_score(x, x**2)
print (m.mic())
距离相关度

距离相关系数是为了克服Pearson相关系数的弱点而生的。在x和x^2这个例子中,即便Pearson相关系数是0,我们也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是0,那么我们就可以说这两个变量是独立的。

这里写代码片

过滤型(Fillter)缺点:没有考虑到特征之间的关联作用,可能把有用的关联特征误踢掉。
sklearn.feature_selection
这里写图片描述


方法2:包裹型(Wrapper)

递归特征删除算法

把特征选择看做一个特征子集搜索问题,筛选各种特征子集,用模型评估效果。 典型的包裹型算法为 “递归特征删除算法”(recursive feature elimination algorithm)
比如用逻辑回归,怎么做这个事情呢?
①用全量特征跑一个模型
② 根据线性模型的系数(体现相关性),删掉5-10%的弱特征,观
察准确率/auc的变化
③ 逐步进行,直至准确率/auc出现大的下滑停止
sklearn中用到的是sklearn.feature_selection.RFE
这里写图片描述
这里写图片描述
返回的是特征贡献的排序情况

基于学习模型的特征排序 (Model based ranking)

这种方法的思路是直接使用你要用的机器学习算法,针对每个单独的特征和响应变量建立预测模型。其实Pearson相关系数等价于线性回归里的标准化回归系数。假如某个特征和响应变量之间的关系是非线性的,可以用基于树的方法(决策树、随机森林)、或者扩展的线性模型等。基于树的方法比较易于使用,因为他们对非线性关系的建模比较好,并且不需要太多的调试。但要注意过拟合问题,因此树的深度最好不要太大,再就是运用交叉验证。

from sklearn.cross_validation import cross_val_score, ShuffleSplit
from sklearn.datasets import load_boston#波士顿房屋价格预测
from sklearn.ensemble import RandomForestRegressor
#集成学习ensemble库中的随机森林回归RandomForestRegressor

#Load boston housing dataset as an example
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]

rf = RandomForestRegressor(n_estimators=20, max_depth=4)
#20个弱分类器,深度为4
scores = []
for i in range(X.shape[1]):#分别让每个特征与响应变量做模型分析并得到误差率
     score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2",
                              cv=ShuffleSplit(len(X), 3, .3))
     scores.append((round(np.mean(score), 3), names[i]))
print (sorted(scores, reverse=True))#对每个特征的分数排序

方法3:嵌入型(Embeded)

根据模型来分析特征的重要性(有别于上面的方式,是从生产的模型权重等)。最常见的方式为用正则化方式来做特征选择。
举个例子,最早在电商用LR做CTR预估,在3-5亿维的系数特征上用L1正则化的LR模型。剩余2-3千万的feature,意味着其他的feature重要度不够。

正则化模型

正则化就是把额外的约束或者惩罚项加到已有模型(损失函数)上,以防止过拟合并提高泛化能力。损失函数由原来的E(X,Y)变为E(X,Y)+alpha||w||,w是模型系数组成的向量(有些地方也叫参数parameter,coefficients),||·||一般是L1或者L2范数,alpha是一个可调的参数,控制着正则化的强度。当用在线性模型上时,L1正则化和L2正则化也称为Lasso和Ridge。
Lasso
L1正则化 是指向量中各个元素绝对值之和,将系数w的l1范数作为惩罚项加到损失函数上,由于正则项非零,这就迫使那些弱的特征所对应的系数变成0。因此L1正则化往往会使学到的模型很稀疏(系数w经常为0),这个特性使得L1正则化成为一种很好的特征选择方法。L1正则化像非正则化线性模型一样也是不稳定的,如果特征集合中具有相关联的特征,当数据发生细微变化时也有可能导致很大的模型差异。
Ridge
L2范数是指向量各元素的平方和然后求平方根,将系数向量的L2范数添加到了损失函数中。由于L2惩罚项中系数是二次方的,这使得L2和L1有着诸多差异,最明显的一点就是,L2正则化会让系数的取值变得平均。对于关联特征,这意味着他们能够获得更相近的对应系数。还是以Y=X1+X2为例,假设X1和X2具有很强的关联,如果用L1正则化,不论学到的模型是Y=X1+X2还是Y=2X1,惩罚都是一样的,都是2alpha。但是对于L2来说,第一个模型的惩罚项是2alpha,但第二个模型的是4*alpha。可以看出,系数之和为常数时,各系数相等时惩罚是最小的,所以才有了L2会让各个系数趋于相同的特点。
L2正则化对于特征选择来说一种稳定的模型,不像L1正则化那样,系数会因为细微的数据变化而波动。所以L2正则化和L1正则化提供的价值是不同的,L2正则化对于特征理解来说更加有用:表示能力强的特征对应的系数是非零。
这里写图片描述

from sklearn.feature_selection import RFE                #包裹型特征选择
from sklearn.preprocessing import StandardScaler    #数据标准化
from sklearn.cross_validation import train_test_split  #交叉验证
import matplotlib.pyplot as plt 
from sklearn.linear_model import LinearRegression  #线性回归
from sklearn.datasets import load_boston     
import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import Ridge                   #L2正则化
from sklearn.linear_model import Lasso                   #L1正则化

#数据导入
boston=load_boston()                          
scaler = StandardScaler()                                        #数据标准化
X=scaler.fit_transform(boston.data)                        #特征变量的数据
y=boston.target                                                      #结果-->房价
names=boston.feature_names                                  #特征名

#算法拟合
lr=LinearRegression()              #线性回归算法
rfe=RFE(lr,n_features_to_select=1) 
rfe.fit(X,y)                              #拟合数据

print("原有特征名:")
print("\t",list(names))
print("排序后的特征名:")
print("\t",sorted(zip(map(lambda x: round(x,4),rfe.ranking_),names))) #对特征进行排序

#提取排序后的属性在原属性列的序列号
rank_fea=sorted(zip(map(lambda x: round(x,4),rfe.ranking_),names))   #排序好的特征
rank_fea_list=[]                                              #用来装排序的特征的属性名
for i in rank_fea:
    rank_fea_list.append(i[1])  
index_list=[0]*13                                         #记录特征属性名对应原属性names的序列号
for j,i in enumerate(rank_fea_list):
    index=list(names).index(i) #获取序列号
    index_list[j]=index
print("排序后特征对应原特征名的序列号:")
print("\t",index_list)
print("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
'''
#如果想要看一看每个特征与结果之间的散点分布情况的话,请把''' ''''去掉即可,即把注释符号去掉
#给予排序号的每个特征和结果画图,看看每个特征和结果之间的关系
'''
for i in index_list:                                #共有13个特征,所以画13张图
    plt.figure(names[i])            #每张图以该特征为名
    plt.scatter(X[:,i],y)             #画出散点图
    plt.xlabel(names[i])
    plt.ylabel("price house")
#提取排名前n个特征的算法拟合
print("提取排序后的前n个特征向量进行训练:")
for time in range(2,13):
    X_exc=np.zeros((X.shape[0],time))     #把排序好前六个特征向量提取出来,放在X—exc矩阵里
    for  j,i in enumerate(index_list[:time]):
        X_exc[:,j]=X[:,i]

    X_train1,X_test1,y_train1,y_test1=train_test_split(X_exc,y)
    lr1=LinearRegression()
    lr1.fit(X_train1,y_train1)
    print("\t提取{0}个的特征-->R方值\t".format(time),lr1.score(X_test1,y_test1))
print()

#原数据全部特征拟合
print("全部特征向量进行训练:")
X_train_raw,X_test_raw,y_train_raw,y_test_raw=train_test_split(X,y)
lr_raw=LinearRegression()
lr_raw.fit(X_train_raw,y_train_raw)
print("\t全部特征---->R方值\t",lr_raw.score(X_test_raw,y_test_raw))
print()

#只提取一个特征向量
print("只提取一个特征向量进行训练:")
for i in index_list:
    X2=np.zeros((X.shape[0],1))
    X2[:,0]=X[:,index_list[i]]
    X_train2,X_test2,y_train2,y_test2=train_test_split(X2,y)
    lr2=LinearRegression()
    lr2.fit(X_train2,y_train2)
    print("\t特征",names[i],"---->R方值","\t",lr2.score(X_test2,y_test2))
print()

#采取L1正则化的方法
print("采取L1正则化的方法:")
lasso= Lasso(alpha=0.3)        #alpha参数由网友用网格搜索方法确定下来的
lasso.fit(X_train_raw,y_train_raw)
print("\tL1正则化特征---->R方值\t",lasso.score(X_test_raw,y_test_raw))
print()

#采取L2正则化的方法
print("采取L2正则化的方法")
ridge = Ridge(alpha=10)         #alpha参数由网友用网格搜索方法确定下来的
ridge.fit(X_train_raw,y_train_raw)
print("\tL2正则化特征---->R方值\t",ridge.score(X_test_raw,y_test_raw))
plt.show()        #显示图片

例子中用到基于线性模型用到RFE,正则化等方法,也看出特征选择后对结论的影响。特征选择是进行模型训练前的最后一步,是数据加工过程的最后一步,几乎每个例子中都会涉及到。
如前面所述,在机器学习领域大部分时间将会与数据打交道,因此,在学习算法的过程中一定要利用python把数据玩儿的很溜,边学python边学数据!!!
PS
正则化是一个比较绕人的问题,下一篇会专门讲正则化,会参考几篇CSDN的博客加上自己的理解。

参考链接:
CSDN.Feature Engineering
Feature_Selection方法总结
老外总结.Part1
老外总结.Part2
知乎.Feature_Selection

  • 21
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
特征工程是指从原始数据中提取特征并将其转换为适合机器学习模型的格式。它是机器学习流程中一个极其关键的环节,因为正确的特征可以减轻构建模型的难度,从而使机器学习流程输出更高质量的结果。在sklearn中,有多种方法可以进行特征工程。 一种常见的方法是使用StandardScaler类实现列标准化。这个类可以将每个特征的值转换为均值为0,方差为1的标准正态分布。例如,可以使用以下代码对特征进行标准化: ```python import numpy as np from sklearn.preprocessing import StandardScaler X_train = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]) std = StandardScaler() X_train_std = std.fit_transform(X_train) ``` 另一种方法是使用基于树的方法(如决策树、随机森林)或扩展的线性模型来处理非线性关系。这些方法对于非线性关系的建模效果较好,并且不需要太多的调试。例如,可以使用以下代码对波士顿房屋价格数据集进行特征处理: ```python from sklearn.cross_validation import cross_val_score, ShuffleSplit from sklearn.datasets import load_boston from sklearn.ensemble import RandomForestRegressor boston = load_boston() X = boston["data"] Y = boston["target"] names = boston["feature_names"] rf = RandomForestRegressor(n_estimators=20, max_depth=4) scores = [] for i in range(X.shape[1]): score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2", cv=ShuffleSplit(len(X), 3, .3)) scores.append((round(np.mean(score), 3), names[i])) print(sorted(scores, reverse=True)) ``` 除了以上方法,还有其他一些特征处理的技术,如特征选择、特征降维等。特征工程的目的是提取有用的特征,减少无用的特征,并为机器学习模型提供更好的输入。通过合适的特征工程,可以提高模型的性能和准确性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值