一.概念
学习过Machine Learning的一定听过这句话:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。
所谓特征工程,做的就是【最大限度地从原始数据中提取特征点以供算法和模型使用】这么一件事。
二.模块
特征工程大体可以分为以下几大模块
1.特征采集:主要基于业务理解,找出满足需求的数据,设计如何获取及存储特征点,并且评估其准确率、覆盖率、采集难度等
2.特征处理:
2.1采样:合法样本筛选(排除异常样本)、样本权重、数据不均衡等处理
2.2预处理:
2.2.1单特征:归一化、离散化、数据变换、缺失值等
2.2.2多特征:降维(PCA、LDA)、迭代特征子集(完全搜索、启发式搜索)、决策树等
3.特征校正:特征有效性分析、特征监控、模型维护
三.常用方法
很多人都选择scikit-learn,因为其提供了较为完整的特征处理方法,包括数据处理,特征选择,降维等
数据处理相关:
标准化
from sklearn.preprocessing import StandardScaler#标准化,返回值为标准化后的数据StandardScaler().fit_transform(data)
区间缩放法
from sklearn.preprocessing import MinMaxScaler#区间缩放,返回值为缩放到[0, 1]区间的数据MinMaxScaler().fit_transform(data)
归一化
from sklearn.preprocessing import Normalizer#归一化,返回值为归一化后的数据Normalizer().fit_transform(data)
二值化
from sklearn.preprocessing import Binarizer#二值化,阈值设置为3,返回值为二值化后的数据Binarizer(threshold=3).fit_transform(data)
缺失值计算
from numpy import vstack, array, nanfrom sklearn.preprocessing import Imputer#缺失值计算,返回值为计算缺失值后的数据#参数missing_value为缺失值的表示形式,默认为NaN#参数strategy为缺失值填充方式,默认为mean(均值)Imputer().fit_transform(vstack((array([nan, nan, nan, nan]), data)))
数据转换
preproccessing库提供了PolynomialFeatures()、FunctionTransformer()等方法可以进行常用函数转换
from sklearn.preprocessing import PolynomialFeatures#多项式转换#参数degree为度,默认值为2PolynomialFeatures().fit_transform(data)from numpy import log1pfrom sklearn.preprocessing import FunctionTransformer#自定义转换函数为对数函数的数据变换#第一个参数是单变元函数FunctionTransformer(log1p).fit_transform(data)
数据选择相关:
方差选择法
from sklearn.feature_selection import VarianceThreshold#方差选择法,返回值为特征选择后的数据#参数threshold为方差的阈值VarianceThreshold(threshold=3).fit_transform(data)
相关系数法
from sklearn.feature_selection import SelectKBestfrom scipy.stats import pearsonr#选择K个最好的特征,返回选择特征后的数据#第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数#参数k为选择的特征个数SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(data, target)
卡方检验
from sklearn.feature_selection import SelectKBestfrom sklearn.feature_selection import chi2#选择K个最好的特征,返回选择特征后的数据SelectKBest(chi2, k=2).fit_transform(data, target)
互信息法
from sklearn.feature_selection import SelectKBestfrom minepy import MINE#由于MINE的设计不是函数式的,定义mic方法将其为函数式的,返回一个二元组,二元组的第2项设置成固定的P值0.5def mic(x, y):m = MINE()m.compute_score(x, y)return (m.mic(), 0.5)#选择K个最好的特征,返回特征选择后的数据SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(data, target)
Wrapper递归特征消除法
from sklearn.feature_selection import RFEfrom sklearn.linear_model import LogisticRegression#递归特征消除法,返回特征选择后的数据#参数estimator为基模型#参数n_features_to_select为选择的特征个数RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(data, target)
Embedded惩罚项特征选择法
from sklearn.feature_selection import SelectFromModelfrom sklearn.linear_model import LogisticRegression#带L1惩罚项的逻辑回归作为基模型的特征选择SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(data, target)
实际上,L1惩罚项降维的原理在于保留多个对目标值具有同等相关性的特征中的一个,所以没选到的特征不代表不重要。故,可结合L2惩罚项来优化。具体操作为:若一个特征在L1中的权值为1,选择在L2中权值差别不大且在L1中权值为0的特征构成同类集合,将这一集合中的特征平分L1中的权值,故需要构建一个新的逻辑回归模型:
from sklearn.linear_model import LogisticRegressionclass LR(LogisticRegression):def __init__(self, threshold=0.01, dual=False, tol=1e-4, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver='liblinear', max_iter=100, multi_class='ovr', verbose=0, warm_start=False, n_jobs=1):#权值相近的阈值self.threshold = thresholdLogisticRegression.__init__(self, penalty='l1', dual=dual, tol=tol, C=C,fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight=class_weight,random_state=random_state, solver=solver, max_iter=max_iter,multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)#使用同样的参数创建L2逻辑回归self.l2 = LogisticRegression(penalty='l2', dual=dual, tol=tol, C=C, fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight = class_weight, random_state=random_state, solver=solver, max_iter=max_iter, multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)def fit(self, X, y, sample_weight=None):#训练L1逻辑回归super(LR, self).fit(X, y, sample_weight=sample_weight)self.coef_old_ = self.coef_.copy()#训练L2逻辑回归self.l2.fit(X, y, sample_weight=sample_weight)cntOfRow, cntOfCol = self.coef_.shape#权值系数矩阵的行数对应目标值的种类数目for i in range(cntOfRow):for j in range(cntOfCol):coef = self.coef_[i][j]#L1逻辑回归的权值系数不为0if coef != 0:idx = [j]#对应在L2逻辑回归中的权值系数coef1 = self.l2.coef_[i][j]for k in range(cntOfCol):coef2 = self.l2.coef_[i][k]#在L2逻辑回归中,权值系数之差小于设定的阈值,且在L1中对应的权值为0if abs(coef1-coef2) < self.threshold and j != k and self.coef_[i][k] == 0:idx.append(k)#计算这一类特征的权值系数均值mean = coef / len(idx)self.coef_[i][idx] = meanreturn self
结合带L1以及L2惩罚项:
from sklearn.feature_selection import SelectFromModel#带L1和L2惩罚项的逻辑回归作为基模型的特征选择#参数threshold为权值系数之差的阈值SelectFromModel(LR(threshold=0.5, C=0.1)).fit_transform(data, target)
基于树模型的特征选择法
from sklearn.feature_selection import SelectFromModelfrom sklearn.ensemble import GradientBoostingClassifier#GBDT作为基模型的特征选择SelectFromModel(GradientBoostingClassifier()).fit_transform(data, target)
降维相关:
常见的降维方法有主成分分析法(PCA)和线性判别分析(LDA),线性判别分析本身也是一个分类模型。PCA和LDA有很多的相似点,其本质是要将原始的样本映射到维度更低的样本空间中,但是PCA和LDA的映射目标不一样:PCA是为了让映射后的样本具有最大的发散性;而LDA是为了让映射后的样本有最好的分类性能。所以说PCA是一种无监督的降维方法,而LDA是一种有监督的降维方法。
PCA
from sklearn.decomposition import PCA#主成分分析法,返回降维后的数据#参数n_components为主成分数目PCA(n_components=2).fit_transform(data)
LDA
from sklearn.lda import LDA#线性判别分析法,返回降维后的数据#参数n_components为降维后的维数LDA(n_components=2).fit_transform(data, target)
四.总结
特征工程比较核心的模块就是特征的预处理,说白了就是在进入算法前解决输入数据信息冗余、存在值缺失等问题。
所以很多时候,机器学习中对于数据提取特征的好坏程度可能比算法、模型还重要。
五.相关学习资源
http://scikit-learn.org/stable/index.html
https://www.zhihu.com/question/29316149