文前提要特征工程概述
特征选择的一般步骤
特征工程的主要包含的内容框架
特征选择的主要方法和python与R的比较实现
目录
1.特征工程概述
2.特征工程知识框架
3.特征工程的一般步骤
4.特征选择的python与R实现比较
4.1 导入数据
4.2 数据预处理
4.2.1 标准化
4.2.2 区间放缩法
4.2.3 归一化
4.2.4 对定量特征二值化
4.2.5 对定性特征哑编码
4.2.6 缺失值填补
4.2.7 数据变换
4.3 特征选择
4.3.1 Filter法(过滤法)
4.3.2 Wrapper法(封装法)
4.3.3 Embedded(集成法)
4.4降维
4.4.1PCA
4.4.2LDA
1.特征工程概述
特征工程其实是一个偏工程的术语,在数据库领域可能叫做属性选择,而在统计学领域叫变量选择,其实是一个意思:即最大限度地从原始数据中提取有用信息以供算法和模型使用,通过寻求最优特征子集等方法使模型预测性能最高。当然,网络上对特征工程的总结已经非常成熟了(详见jasonfreak的知乎问答:使用sklearn做单机特征工程。但本人将依据python代码的实习,总结用R来实现,以方便对特征工程全面的总结和理解。本文总结主要依据jasonfreak的“使用sklearn做单机特征工程”总结,在此对其的深刻总结表示感谢。
2.特征工程知识框架
jasonfreak总结出了特征工程的主要知识框架,如下图:
Alt text
3.特征工程的一般步子集产生:按照一定搜索策略产生候选特征子集;
子集评估:通过某个评价函数评估子集的优劣;
停止条件:决定特征选择算法什么时候停止;
子集验证:验证最终所选子集的有效性。
Alt text
4.特征选择的python与R实现比较
4.1导入数据
我们以经典的鸢尾花数据iris为例,分别根据已有的特征选择的框架图,本人结合网络上给出的python代码总结,添加了运用R实现特征选择的方法,来对比两种语言的差异。
python:
from sklearn.datasets import load_iris
#导入数据集
iris = load_iris()
#特征矩阵
iris.data
#目标向量
iris.target
R:
data("iris")
# 特征矩阵
iris.data <- iris[, -length(iris)]
# 目标向量
iris.targer <- iris[, length(iris)]
4.2数据预处理
4.2.1标准化(要求数据符合正态性)
python:
from sklearn.preprocessing import StandardScaler
StandardScaler().fit_transform(iris.data)
R:
scale(iris.data, center = TRUE, scale = TRUE)
# 或者运用BBmisc包中的normalize函数
normalize(iris.data)
4.2.2区间放缩法
python:
from sklearn.preprocessing import MinMaxScaler
MinMaxScaler().fit_transform(iris.data)
R:
# 依据公式构建区间放缩函数
maxmin <- function(col) {
maxmin <- (col - min(col))/(max(col) - min(col))
return(maxmin)}
maxmin(iris.data)
4.2.3归一化
此处的归一化是指依照特征矩阵的行处理数据,其目的在于样本向量在点乘运算或其他核函数计算相似性时,拥有统一的标准,也就是说都转化为“单位向量”.归一化后样本各属性的平方和为1.
python:
from sklearn.preprocessing import Normalizer
Normalizer().fit_transform(iris.data)
R:
norm <- function(data) {
norm = apply(data, 1, function(x) {
x/sqrt(sum(x^2))
})
norm = t(norm)
return(norm)}norm(iris.data)
标准化与归一化的区别:
标准化是依照特征矩阵的列处理数据,其通过求z-score的方法,转换为标准正态分布。而归一化是将样本的特征值转换到同一量纲下把数据映射到[0,1]区间内,因此区间放缩法是归一化的一种。
4.2.4对定量特征二值化
以某个值为阈值,转换为0,1变量。
python:
from sklearn.preprocessing import Binarizer
Binarizer(threshold=3).fit_transform(iris.data)
R:
bina <- function(data, threshold) {
ifelse(data > threshold, 1, 0)}
bina(iris.data, threshold = 3)
4.2.5对定性特征哑编码
python:
from sklearn.preprocessing import OneHotEncoder
OneHotEncoder().fit_transform(iris.target.reshape((-1,1)))
R:
library(caret)
var <- dummyVars(~Species, data = iris)
predict(var, iris["Species"])
4.2.6缺失值填补
新增一个样本,缺失值为NAN,并对缺失值进行填补。
python:
from numpy import vstack, array, nan
from sklearn.preprocessing import Imputer
#参数strategy为缺失值填充方式,默认为mean(均值)
Imputer().fit_transform(vstack((array([nan, nan, nan, nan]), iris.data)))
R:
new = rep(NA, 4)
iris.data <- rbind(new, iris.data)
library(Hmisc)
impute(iris.data, mean)
4.2.7数据变换
常见的数据变换有基于多项式的、基于指数函数的、基于对数函数等.
python:
#多项式转换
from sklearn.preprocessing import PolynomialFeatures
#参数degree为度,默认值为2
PolynomialFeatures().fit_transform(iris.data)
#对数函数转换
from numpy import log1p
from sklearn.preprocessing import FunctionTransformer
FunctionTransformer(log1p).fit_transform(iris.data)
R:
# 多项式转换
library(dplyr)
iris.data <- iris.data %>%
mutate(x3 = Sepal.Length * Sepal.Width)# 对数函数转换
iris.data <- iris.data %>%
mutate_each(funs(log1p))
4.3特征选择
4.3.1Filter法(过滤法)
按照变量内部特征或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数选择特征.与特定的学习算法无关,因此具有较好的通用性,作为特征的预筛选器非常合适。缺点主要是由于算法的评价标准独立于特定的学习算法,所选的特征子集在分类准确率方面通常低于Wrapper方法。
1.方差选择法
计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征.
python:
from sklearn.feature_selection import VarianceThreshold
#参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(iris.data)
R:
library(mlr)
# 创建task
train.task <- makeClassifTask(data = iris, target = "Species")
# 查看变量选择可选方法listFilterMethods()
# 选择计算方差,进行特征选择
var_imp <- generateFilterValuesData(train.task, method = "variance", nselect = 3)
var_imp
# 对衡量特征指标进行绘图
plotFilterValues(var_imp, feat.type.cols = TRUE, n.show = 3)
2.相关系数法
计算各个特征对目标值的相关系数以及相关系数的P值.
python:
from sklearn.feature_selection import SelectKBest
from 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(iris.data, iris.target)
R:
library(mlr)
# 创建task
train.task <- makeRegrTask(data = iris.data, target = "Sepal.Width")
# 查看变量选择可选方法
listFilterMethods()
# 选择pearson相关系数,进行特征选择 也可以选择秩相关系数(method =# rank.correlation)
var_imp <- generateFilterValuesData(train.task, method = "linear.correlation")
var_imp
# 对相关系数进行绘图
library(corrplot)
corrplot(cor(iris.data), order = "hclust")
3.计算卡方值
经典的卡方检验是检验定性自变量对定性因变量的相关性,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,这个统计量的含义简而言之就是自变量对因变量的相关性.
python:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)
R:
library(mlr)
# 创建task
train.task <- makeClassifTask(data = iris, target = "Species")
# 查看变量选择可选方法
listFilterMethods()
# 选择计算卡方值,进行特征选择
var_imp <- generateFilterValuesData(train.task, method = "chi.squared")
var_imp
# 对衡量特征指标进行绘图
plotFilterValues(var_imp, feat.type.cols = TRUE)
4.互信息
经典的互信息也是评价定性自变量对定性因变量的相关性的,可以看成是一个随机变量中包含的关于另一个随机变量的信息量.
python:
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的设计不是函数式的,定义mic方法将其为函数式的,
#返回一个二元组,二元组的第2项设置成固定的P值0.5
def 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(iris.data, iris.target)
R:
library(mlr)
# 创建task
train.task <- makeClassifTask(data = iris, target = "Species")
# 查看变量选择可选方法
listFilterMethods()# 选择计算信息增益,进行特征选择
var_imp <- generateFilterValuesData(train.task, method = "information.gain")
var_imp
# 对衡量特征指标进行绘图
plotFilterValues(var_imp, feat.type.cols = TRUE)
4.3.2 Wrapper法(封装法)
封装式特征选择是利用学习算法的性能来评价特征子集的优劣。因此,对于一个待评价的特征子集,Wrapper方法需要训练一个分类器,根据分类器的性能对该特征子集进行评价,学习算法包括决策树、神经网络、贝叶斯分类器、近邻法以及支持向量机等。Wrapper方法缺点主要是特征通用性不强,当改变学习算法时,需要针对该学习算法重新进行特征选择。
1.递归特征消除法
递归消除特征法使用一个模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。Logistic回归的R实现详见本微信公众号历史文章:Logistic回归详解(三)——变量选择部分。
python:
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#递归特征消除法,返回特征选择后的数据
#参数estimator为基模型
#参数n_features_to_select为选择的特征个数
RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)
R:
# 构建Logistic回归模型
library(MASS)
m <- glm(Species ~ ., data = iris, family = "binomial")
# 运用step函数进行变量选择
selecting <- step(m, direction = "backward")
4.3.3 Embedded(集成法)
在集成法特征选择中,特征选择算法本身作为组成部分嵌入到学习算法里。最典型的即决策树算法。包括基于惩罚项的特征选择法和基于树模型的特征选择法。
1.基于惩罚项的特征选择法
其中R实现详见本微信公众号历史文章:正则化及其R实现。
python:
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择(lasso回归)
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
R:
# 转换变量类型
iris.matrix <- as.matrix(iris.data)
target <- as.numeric(iris.targer)
# Lasso回归
library(glmnet)
# alpha = 1为Lasso回归,alpha=0为岭回归
r2 <- glmnet(iris.matrix, target, family = "multinomial", alpha = 1)
# 通过10fold交叉验证获得最优lambda参数
r2.cv <- cv.glmnet(iris.matrix, target, family = "multinomial", alpha = 1, nfolds = 10)
plot(r2.cv)
# 根据获得的lambda.min值,拟合最优模型r2.min
r2.min <- glmnet(iris.matrix, target, family = "multinomial", alpha = 1, lambda = r2.cv$lambda.min)
r2.min_coef <- coef(r2.min)
2.基于树模型的特征选择法
python:
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT作为基模型的特征选择
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)
R:
library(mlr
)train.task <- makeClassifTask(data = iris, target = "Species")
# 查看可选模型参数
listLearners("classif", "multiclass")[c("class", "package")]
# 创建机器学习模型
gbm_learner <- makeLearner("classif.gbm", predict.type = "response")
# 设定模型参数
gbm_learner$par.vals <- list(laplace = 1)
# 训练和预测
nB_models <- mlr::train(gbm_learner, train.task)
nB_predict <- predict(nB_models, train.task)
# 模型评估
nB_prediction <- nB_predict$data$response
# 混淆矩阵
dCM <- confusionMatrix(iris$Species, nB_prediction)
4.4降维
降维方法除了以上提到的基于L1惩罚项的模型以外,另外还有主成分分析法(PCA)和线性判别分析(LDA),线性判别分析本身也是一个分类模型。PCA和LDA有很多的相似点,其本质是要将原始的样本映射到维度更低的样本空间中,但是PCA和LDA的映射目标不一样:PCA是为了让映射后的样本具有最大的发散性;而LDA是为了让映射后的样本有最好的分类性能。所以说PCA是一种无监督的降维方法,而LDA是一种有监督的降维方法。
4.4.1主成分分析(PCA)
python:
from sklearn.decomposition import PCA
#主成分分析法,返回降维后的数据
#参数n_components为主成分数目
PCA(n_components=2).fit_transform(iris.data)
R:
# 主成分分析
iris.pc <- prcomp(iris.data)summary(iris.pc)
# 主成分分析陡坡图
plot(iris.pc, type = "l", main = "PCA陡坡图")
4.4.2线性判别分析(LDA)
python:
from sklearn.lda import LDA
#线性判别分析法,返回降维后的数据
#参数n_components为降维后的维数
LDA(n_components=2).fit_transform(iris.data, iris.target)
R:
library(MASS)
# 以公式格式进行线性判别
fit_lda = lda(Species ~ ., data = iris)
names(fit_lda)
fit_lda$means
要想获取分析代码,可查看原文,进入本人的GitHubhttps://github.com/Alven8816查看下载,或通过本人邮箱[email protected]与本人联系
------------------------------------------
作者:余文华
公众号:乐享数据DataScientists
大家也可以加小编微信:tsbeidou (备注:知乎),进R语言中文社区 交流群,可以跟各位老师互相交流