特征变换是指对原始的某个特征通过一定规则或映射得到新特征的方法。常见的特征变化有:
概念分层
标准化
离散化
函数变换
深入表达 等
特征变换主要由人工完成,属于比较基础的特征构建方法。
将类别过多的变量通过使用概念分层的变换方法得到类别较少的变量,比如可以将年龄变量“1岁”“2岁”“3岁”…等,变换为更高概念层次的值,如“儿童”“青年”“中年”等,
这里通过r语言,使用身体发育数据集,介绍概念分层的用法。
代码如下:
> #加载数据集
> boysData<-read.csv("boysData.csv")
> #属性说明
> #age:年龄
> #hgt:身高
> #wgt:体重
> #bmi:体重指数
> #hc:头尾
> #gen:发育程度1
> #phb:发育程度2
> #tv:发育程度3
> #reg:所属区域
> print(head(boysData))
X age hgt wgt bmi hc gen phb tv reg
1 1 0.035 50.1 3.650 14.54 33.7 NA NA NA south
2 2 0.038 53.5 3.370 11.77 35.0 NA NA NA south
3 3 0.057 50.0 3.140 12.56 35.2 NA NA NA south
4 4 0.060 54.5 4.270 14.37 36.7 NA NA NA south
5 5 0.062 57.5 5.030 15.21 37.3 NA NA NA south
6 6 0.068 55.5 4.655 15.11 37.0 NA NA NA south
> ## age hgt wgt bmi hc gen phb tv reg
> ## 1 0.035 50.1 3.650 14.54 33.7 NA south
> ## 2 0.038 53.5 3.370 11.77 35.0 NA south
> ## 3 0.057 50.0 3.140 12.56 35.2 NA south
> ## 4 0.060 54.5 4.270 14.37 36.7 NA south
> ## 5 0.062 57.5 5.030 15.21 37.3 NA south
> ## 6 0.068 55.5 4.655 15.11 37.0 NA south
> summary(boysData)
X age hgt wgt bmi hc
Min. :1.00 Min. :0.03500 Min. :50.00 Min. :3.140 Min. :11.77 Min. :33.70
1st Qu.:2.25 1st Qu.:0.04275 1st Qu.:50.95 1st Qu.:3.440 1st Qu.:13.01 1st Qu.:35.05
Median :3.50 Median :0.05850 Median :54.00 Median :3.960 Median :14.46 Median :35.95
Mean :3.50 Mean :0.05333 Mean :53.52 Mean :4.019 Mean :13.93 Mean :35.82
3rd Qu.:4.75 3rd Qu.:0.06150 3rd Qu.:55.25 3rd Qu.:4.559 3rd Qu.:14.97 3rd Qu.:36.92
Max. :6.00 Max. :0.06800 Max. :57.50 Max. :5.030 Max. :15.21 Max. :37.30
gen phb tv reg
Mode:logical Mode:logical Mode:logical Length:6
NA's:6 NA's:6 NA's:6 Class :character
Mode :character
> ## 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)
X age hgt wgt bmi hc gen phb tv reg wtype
1 1 0.035 50.1 3.650 14.54 33.7 NA NA NA south 过轻
2 2 0.038 53.5 3.370 11.77 35.0 NA NA NA south 过轻
3 3 0.057 50.0 3.140 12.56 35.2 NA NA NA south 过轻
4 4 0.060 54.5 4.270 14.37 36.7 NA NA NA south 过轻
5 5 0.062 57.5 5.030 15.21 37.3 NA NA NA south 过轻
6 6 0.068 55.5 4.655 15.11 37.0 NA NA NA south 过轻
> barplot(table(boysData$wtype),col=rainbow(9),border='gray')
标准化是对数据进行无量纲处理,使数据在同一个横向上比较,消除量纲不同产生的影响和误差。
标准化分为线性标准化和非线性标准化两类
线性标准化:即是满足y=ax+b形式的标准化处理过程,常见的线性标准化处理有极差标准化,zscore标准化,小数定标标准化等
极差标准化(归一化):
极差标准化适用于知道这组数据的最大值和最小值的情况,通过最大值和最小值,将数据中的每个值转化为【0,1】之间的数据。
对于正向指标公式:
对于逆向指标:
zscore标准化:
zscore标准化是将数据转化为N(0,1)的标准正态分布得分的标准化方法,(可适应于不知道最大值和最小值的情况),对于数据x1,,,xn,假设均值为μ,方差为б,则对应的标准化公式为:
小数定标标准化等:
在不知道数据最大值最小值和数据的基本信息的情况下,可通过小数定标标准化。它是基于等比例缩减数据范围的思路,通过移动小数点实现标准化。小数点移动多少位取决于属性A的取值中的最大绝对值。例如:属性A的取值范围是-800到70,那么就可以将数据的小数点整体向左移三位即[-0.8,0.07]。
标准化公式如下:
非线性标准化:所谓非线性标准化,就是标准化处理过程是非线性的,常见的有:对数标准化、倒数标准化等。
对数标准化:
对数函数 log(x) 的曲线随着 x 的增加,曲线逐渐变缓,根据这种特性在某些场景做标准化,比如通过用户的购买次数来分析客户的满意度。
正向指标的标准化处理公式:
对于逆向指标:
其中a、b为常数,c是比max(x)大一点的常数。a、b可根据yi对数据取值的限定得出。
倒数标准化
倒数标准化适用于反向指标,若数据全部为正实数,则标准化结果介于[0.1]之间,反之,则介于[-1,0]之间。若两边都有,则介于[-1,1]。
倒数标准化处理公式
a是x1,,,xn中非零的最小绝对值
先用r代码实现上述标准化处理方法:
#该函数用于获取数据的各种标准化值
#x:用于标准化的实数向量
#isPos:是否是正向指标
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,不能进行zscore'标准化")
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))
}
#函数使用
> x<-c(7,8,2,6,10,842,123,564,213,897,484,234)
> stdProc(x,isPos = TRUE)
$yExt
[1] 0.005586592 0.006703911 0.000000000 0.004469274 0.008938547 0.938547486 0.135195531 0.627932961
[9] 0.235754190 1.000000000 0.538547486 0.259217877
$yZsc
[1] -0.8259816 -0.8229834 -0.8409721 -0.8289797 -0.8169872 1.6774471 -0.4781998 0.8439703 -0.2083692
[10] 1.8423436 0.6041208 -0.1454087
$yPot
[1] 0.007 0.008 0.002 0.006 0.010 0.842 0.123 0.564 0.213 0.897 0.484 0.234
$yLog
[1] 0.2635739 0.2862500 0.0000000 0.2367538 0.3232192 0.9906812 0.7066877 0.9316468 0.7879719 1.0000000
[11] 0.9091013 0.8018662
$yInv
[1] 0.285714286 0.250000000 1.000000000 0.333333333 0.200000000 0.002375297 0.016260163 0.003546099
[9] 0.009389671 0.002229654 0.004132231 0.008547009
离散化通常是对于实数而言的,它是将无限的连续取值映射到有限的离散值中。并且这些分类也规定了与连续取值相同的取值区间。比如说将工资的金额,离散化成低等收入,中等收入,高等收入等分类值。离散化可简化数据,提高算法执行效率和模型的可解释性。
常用的离散化方法有:分箱法,熵离散法(没学到以后发),规则离散法(没学到以后发)等
分箱法:
分箱法是将连续型数据按一定的规则存入不同的箱的方法。按箱的宽度和深度,有两种分箱法:等宽分箱和等比分箱。
一个是按数据的个数分,一个是按值分
对于数据 1 2 9 13 17 28 32 43 47 50 56 62 70 73 82 85 共有12个
等比分箱,可以按深度4将数据等分为三个箱内:
等宽分箱可以按宽度40,将数据分到三个箱子内:
分箱后,各分箱分别用什么值来表示?除了可以按取值的范围来定义,还可以对数据做平滑处理。
使用各箱内的平均值
使用各箱内的中位数
使用各箱内的最大值或最小值
在r语言中通常用quantile函数做等比分箱,用cut函数做等宽分箱
#生成100个10到100的随机数
tmpV=runif(100,10,100)
#1.quantile函数分箱,分成四份
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函数等宽分箱,分为五份
c0=cut(tmpV,breaks=5,labels=c("B1","B2","B3","B4","B5"))
#...levels函数可查看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)
}