R小盐准备介绍R语言机器学习与预测模型的学习笔记
你想要的R语言学习资料都在这里, 快来收藏关注【科研私家菜】
01 什么是特征构建
特征对于预测而言是相当重要的,在预测建模之前的大部分工作都是在寻找特征,没有合适特征的预测模型,就几乎等于瞎猜,对预测目标而言没有任何意义。特征通常是指输入数据中对因变量的影响比较明显的有趣变量或属性。常见的特征提取、特征构建、特征选择三个概念有着本质不同,特征提取是指通过函数映射从原始特征中提取新特征的过程,假设有n个原始特征(或属性)表示为A.,A....An,通过特征提取我们可以得到另外一组特征,表示为B,B...,m(m<m),其中Bi = f(A,A2,...An),i∈[1,m]且f是对应的函数映射,注意到,这里我们用得到的新特征替代了原始特征,最终得到m个特征;而特征构建是从原始特征中推断或构建额外特征的过程,对于原始的n个特征A.2....An.经过特征构建,我们得到m个额外的特征,表示为An+.,7....An+m.所得到的这些特征都是由原始特征定义的,最终得到n+m个特征。特征选择是指从原始的n个特征中选择m(m<n)个子特征的过程,因此特征选择按照某个标准实现了最优简化,即实现了降维,最终得到m个特征(注意特征并没有发生变化,只是总的数量减少了)。
特征的构建与选取在提高预测精度方面越来越受到重视,甚至影响到预测项目的成败。通常初始特征是基于领域经验构建的,比如在预测短期负荷的时候,一般会考虑节假日、气温、历史负荷水平等因素来构建特征。然而这样得到的特征未必能够充分地描述目标变量,因此很有必要基于这些初始特征构建更多更强的特征,从而尽可能地提高预测精度。最近几年这方面的研究也不少,百度等科技巨头企业已经有成熟的特征学习算法,并且应用在相关的业务场景中。
02 特征变换
特征变换通常是指对原始的某个特征通过一定规则或映射得到新特征的方法,主要的方法包括概念分层、标准化、离散化、函数变换以及深入表达。特征变换主要是由人工完成,属于比较基础的特征构建方法。
02.1 概念分层
在数据分析过程中,对于类别过多的分类变量通常使用概念分层的方法变换得到类别较少的变量,比如可以将年龄变量,其值为“1岁”、“12岁”、“38岁"等,变换成更高概念层次的值,如“儿童”、“青年"、“中年”等,其中每个值对应多个年龄,经过这样的处理,类别减少到几类,既避免了程序陷入过拟合,又能提高算法的效率。因此,概念分层是缩减离散变量取值数量的方法。由于取值概念层级更高,这必然会损失一些细节信息,极端情况是取到概念分层的顶层,也就是信息损失最大的取值,这种情况下,对所有的样本,该变量的值都是一样的,因此就失去概念分层的意义。
boysData<-read.csv("orgdata.csv")
#属性说明:
#age:年龄
#hgt:身高
#wgt:体重
#bmi:体重指数
#hc:头围
#gen:发育程度1
#phb:发育程度2
#tv:发育程度3
#reg:所属区域
print(head(boysData))
## age hgt wgt bmi hc gen phb tv reg
## 1 0.035 50.1 3.650 14.54 33.7 <NA> <NA> NA south
## 2 0.038 53.5 3.370 11.77 35.0 <NA> <NA> NA south
## 3 0.057 50.0 3.140 12.56 35.2 <NA> <NA> NA south
## 4 0.060 54.5 4.270 14.37 36.7 <NA> <NA> NA south
## 5 0.062 57.5 5.030 15.21 37.3 <NA> <NA> NA south
## 6 0.068 55.5 4.655 15.11 37.0 <NA> <NA> NA south
summary(boysData)
## age hgt wgt bmi
## Min. : 0.035 Min. : 50.00 Min. : 3.14 Min. :11.77
## 1st Qu.: 1.581 1st Qu.: 84.88 1st Qu.: 11.70 1st Qu.:15.90
## Median :10.505 Median :147.30 Median : 34.65 Median :17.45
## Mean : 9.159 Mean :132.15 Mean : 37.15 Mean :18.07
## 3rd Qu.:15.267 3rd Qu.:175.22 3rd Qu.: 59.58 3rd Qu.:19.53
## Max. :21.177 Max. :198.00 Max. :117.40 Max. :31.74
## NA's :20 NA's :4 NA's :21
## hc gen phb tv reg
## Min. :33.70 G1 : 56 P1 : 63 Min. : 1.00 city : 73
## 1st Qu.:48.12 G2 : 50 P2 : 40 1st Qu.: 4.00 east :161
## Median :53.00 G3 : 22 P3 : 19 Median :12.00 north: 81
## Mean :51.51 G4 : 42 P4 : 32 Mean :11.89 south:191
## 3rd Qu.:56.00 G5 : 75 P5 : 50 3rd Qu.:20.00 west :239
## Max. :65.00 NA's:503 P6 : 41 Max. :25.00 NA's : 3
## NA's :46 NA's:503 NA's :522
#这里根据BMI指数,将泛化成体重类型的wtype字段
#通过summary的结果得知bmi字段存在21个缺失值与总量748相比远小于5%,这里将其删除
boysData<-boysData[!is.na(boysData$bmi),]
#设置变换规则
typeUp<-c(18.5,24.99,25,28,32,100)
typeDown<-c(0,18.5,20,25,28,32)
typeName<-c("过轻","正常","适中","过重","肥胖","非常肥胖")
boysData$wtype<-typeName[unlist(mapply(function(x){
tmp<-intersect(which(typeDown<x),which(typeUp>=x))
#如果同时满足正常和适中,则默认为适中
return(tmp[length(tmp)])
},boysData$bmi))]
head(boysData)
## age hgt wgt bmi hc gen phb tv reg wtype
## 1 0.035 50.1 3.650 14.54 33.7 <NA> <NA> NA south 过轻
## 2 0.038 53.5 3.370 11.77 35.0 <NA> <NA> NA south 过轻
## 3 0.057 50.0 3.140 12.56 35.2 <NA> <NA> NA south 过轻
## 4 0.060 54.5 4.270 14.37 36.7 <NA> <NA> NA south 过轻
## 5 0.062 57.5 5.030 15.21 37.3 <NA> <NA> NA south 过轻
## 6 0.068 55.5 4.655 15.11 37.0 <NA> <NA> NA south 过轻
barplot(table(boysData$wtype),col=rainbow(9),border='gray')
02.2 标准化
在数据分析过程中,通常使用的变量量纲不一致,在确定权重、系数、距离的时候,也会有所
影响,因此要进行数据标准化。标准化对数据进行无量纲处理,使不同量纲的数据可以在同一个数量级上进行横向比较,减少因为数据级差异带来的误差。分成线性标准化和非线性标准化两类。
(1)线性标准化
所谓线性标准化,即是满足y= ax + b的标准化处理过程,其中a、b为常数。常见的线性标准
化方法包括极差标准化、z-score 标准化、小数定标标准化。
(2)非线性标准化
非线性标准化,就是标准化处理过程是非线性,常见的包括对数、倒数标准化。
stdProc<-function(x,isPos)
{
#(1)线性标准化
#---极差标准化
if(max(x)>min(x)){
if(isPos){
yExt=(x-min(x))/(max(x)-min(x))
}else{
yExt=(max(x)-x)/(max(x)-min(x))
}
}else{
print("最大值与最小值相等,不能进行极差标准化!")
yExt=NULL
}
#---z-score标准化
sd0<-sd(x)
mean0<-mean(x)
if(sd0==0){
print("由于标准差为0,不能进行z-score标准化")
yZsc=NULL
}else{
yZsc=(x-mean0)/sd0
}
#---小数定标标准化
yPot=x/(10^nchar(max(abs(x))))
#(2)非线性标准化
#---对数标准化
if(isPos){
y=log(x-min(x)+1)
yLog=(1/max(y))*y
}else{
y=log(max(x)-x+1)
yLog=(1/max(y))*y
}
#---倒数标准化
yInv=min(abs(x[x!=0]))/x
return(list(yExt=yExt,yZsc=yZsc,yPot=yPot,yLog=yLog,yInv=yInv))
}
02.3 离散化
离散化通常是对实数而言的,它是将无限的连续值映射到有限分类值中去的方法,并且这些分
类规定了与无限连续值相同的取值空间。比如我们可以将收入金额,取值范围为2000~100000, 离散化成“低等收入”、“中等收入”、“高等收入”等分类值,-般对于这种类型的离散化,得到的是有序分类变量。通过离散化处理,可以简化数据,有助于提高算法的执行效率和模型的可解释性。
常见用于离散化处理的方法主要包括分箱法、熵离散法、ChiMerge法、规则离散法。
(1)分箱法
分箱法是一种将连续数值按照一定规则存放到不同箱中的数据处理方法,箱的宽度表示箱中数
值的取值区间,箱的深度表示箱中数值的数量。通常按箱的等宽、等深的差异将分箱法分成两类,一类是等宽分箱,另一类是等比分箱。
对于数据2、4、7、10、 13、24、26、29、 30、 45、68、89,由于共12个,可以按深度4将数值等比分成3个箱,分别为箱1I: 2、4、7、10;箱2: 13、24、 26、29;箱3: 30、 45、68、89。由于数值介于区间[2,87],可以按宽度44将数值等宽分成2个箱,分别为箱1: 2、4、7、10、13、24、26、29、30、 45;箱2: 68、89。
tmpV=runif(100,10,100)
#1.使用quantile函数进行等比分箱,此处将数据分成4份
newType=c("A1","A2","A3","A4")
q0=quantile(tmpV,probs=seq(0,1,1/4))
v0=rep(newType[1],length(tmpV))
for(i in 2:(length(q0)-1)){
v0[tmpV>q0[i] & tmpV<=q0[i+1]]=newType[i]
}
#...另外常可通过均值、中位数、最大最小值来平滑数值以生成新的特征
vt0=tmpV[tmpV>=q0[1] & tmpV<=q0[2]]
v_mean=rep(mean(vt0),length(tmpV))
v_median=rep(median(vt0),length(tmpV))
v_max=rep(max(vt0),length(tmpV))
v_min=rep(min(vt0),length(tmpV))
for(i in 2:(length(q0)-1)){
v_mean[tmpV>q0[i] & tmpV<=q0[i+1]]=mean(tmpV[tmpV>q0[i] & tmpV<=q0[i+1]])
v_median[tmpV>q0[i] & tmpV<=q0[i+1]]=median(tmpV[tmpV>q0[i] &tmpV<=q0[i+1]])
v_max[tmpV>q0[i] & tmpV<=q0[i+1]]=max(tmpV[tmpV>q0[i] & tmpV<=q0[i+1]])
v_min[tmpV>q0[i] & tmpV<=q0[i+1]]=min(tmpV[tmpV>q0[i] & tmpV<=q0[i+1]])
}
#2.使用cut函数进行等宽分箱,此处将数据分成5份
c0=cut(tmpV,breaks=5,labels=c("B1","B2","B3","B4","B5"))
#...另外可通过设置labels为NULL,并通过levles函数查看cut的水平
#...进一步确定各分箱的取值区间
#...可通过均值、中位数、最大最小值来平滑数值以生成新的特征
L0=levels(cut(tmpV,breaks=5))
v2_mean=v2_median=v2_max=v2_min=rep(0,length(tmpV))
for(lvl in L0)
{
splitval=as.integer(strsplit(strsplit(strsplit(lvl,split='\\(')[[1]][2],
split='\\]')[[1]],split=',')[[1]])
subcond=tmpV>splitval[1] & tmpV<=splitval[2]
subval=tmpV[subcond]
v2_mean[subcond]=mean(subval)
v2_median[subcond]=median(subval)
v2_max[subcond]=max(subval)
v2_min[subcond]=min(subval)
}
(2)熵离散法
熵离散法是基于信息熵的一种数据离散方法,通常用在分类问题的预测场景中对数值属性或特
征进行离散化处理。这是一种有指导的离散化方法,并且通常进行二元离散化。大致思路是这样的,首先对离散化的数值特征进行排序,然后按顺序将对应数值作为分割点,这样可将该特征分为两类,分别记为VI和V2,假设该特征为V,目标变量为U,则该划分可通过计算相应的熵得到信息增益Gains(U,V) = Ent(U) - Ent(UIV),通过不断地选择分割点,并从得到的所有信息增益中,选取最大值,其对应的分割点即为最终用于离散化的分割点。
#将iris中的Sepal.Length变量排序,并保存在变量sortedSL中
sortedSL=sort(iris$Sepal.Length)
#循环:按顺序以sortedSL中的每个值作为分割点,重建新特征new,默认设置为0
gainsV<-NULL
splitV<-NULL
for(i in 1:NROW(sortedSL))
{
splitVal=sortedSL[i]
iris$new=0
if(sum(iris$Sepal.Length>splitVal)>0)
{
iris[iris$Sepal.Length>splitVal,]$new=1
}
gainsV<-c(gainsV,gains(iris$Species,iris$new))
splitV<-c(splitV,splitVal)
}
#分割点为
finalSplitV<-splitV[which.max(gainsV)]
finalSplitV
02.4 函数变换
函数变换指的是使用函数映射将变量或特征变换成另外一个特征的方法。通过函数变换会改变
数据的分布,因此常用于对数据分布比较敏感的模型中。常见的函数变换方法主要包括幂函数变换和对数变换。
关注R小盐,关注科研私家菜(VX_GZH: SciPrivate),有问题请联系R小盐。让我们一起来学习 R语言机器学习与临床预测模型