数据处理-数据规约
在大数据集上进行复杂的数据分析需要很长的时间,数据规约可以产生更小的但保持原数据完整性的新数据集。在规约后的数据集上进行分析将更有效率。数据规约的意义在于:一是降低无效、错误数据对建模的影响,提高建模的准确性;二是少量且具有代表性的数据将大幅缩减数据分析所需要的时间;三是降低储存数据的成本。
1 属性规约(维规约)
属性规约是通过属性合并来创建新属性维数,或者直接通过删除不相关的属性(维)来减少数据维数,从而提高数据分析的效率、降低计算成本。属性规约的目标是寻找出最小的属性子集并确保新数据子集的概率分布尽可能地接近原来数据集的概率分布。属性规约常用的方法有合并属性、逐步向前选择、逐步向后删除、决策树归纳、主成分析等。
合并属性是将一些旧属性合为新属性。用数学语言描述就是:初始属性集:\(\left\{A_1,A_2,A_3,A_4,B_1,B_2,B_3,C\right\}\),合并过程:\(\left\{A_1,A_2,A_3,A_4\right\}\to A,\left\{B_1,B_2,B_3\right\}\to B\),规约后的属性集为\(\left\{A,B,C\right\}\)
逐步向前选择是从一个空属性集开始,每次从原来属性集合中选择一个当前最优的属性添加到当前属性子集中。直到无法选择出最优属性或满足一定阈值约束为止。用数学语言描述是:初始属性集:\(\left\{A_1,A_2,A_3,A_4,A_5,A_6\right\}\),按照某种最优的选择标准(AIC,BIC,\(R^2\)等)先选择当前最优的单属性集,假如是\(A_1\),那么,现在从\(A_1\)开始,按照同样的选择标准添加一个属性,假如是\(A_4\),则现在所选出来的最优子集是\(\left\{A_1,A_4\right\}\),按照这样的方式逐步向前选择。
逐步向后删除和逐步向前选择刚好相反,它是从一个全集开始,每次从当前属性子集中选择一个当前最差的属性并将其从当前属性子集中消去。直到无法选择出最差属性为止或满足一定阈值约束为止。
Lasso在回归分析中,Lasso方法通过在最小二乘回归方程中加入\(l_1\)惩罚项,将回归系数估计向零的方向进行压缩,从而达到属性选择的目的。
决策树归纳是利用决策树的归纳方法对初始数据进行分类归纳学习,获得一个初始决策树,所有没有出现在这个决策树上的属性均可认为是无关属性,因此将这些属性从初始集合中删除,就可以得到一个较优的属性子集。
主成分分析是用较少的变量去解释原始数据中的大部分变量,即将许多相关性很高的变量转化成彼此相互独立或不相关的变量。
决策树归纳方法和主成分分析方法在其他章节中都有详细讲到,合并属性方法理解很直观、操作也很简易,因此这里只具体介绍逐步选择和Lasso方法。
1.1 逐步选择
1.1.1 向前逐步选择
向前逐步选择以一个不包含任何预测变量的零模型为起点,依次往模型中添加变量,直至所有的预测变量都包含在模型中,特别之处在于,每次只将能够最大限度地提升模型效果的变量加入模型中。
向前逐步选择算法流程
- 记不含预测变量的零模型为\(M_0\)
- 对于\(k=0,1,2,…,p-1\):
(a)从p-k个模型中进行选择,每个模型都在模型\(M_k\)的基础上增加一个变量;
(b)在p-k个模型中选择RSS最小或\(R^2\)最高的模型作为最优模型,记为\(M_{k+1}\)。
- 根据AIC,BIC或者调整\(R^2\)从\(M_0,…,M_p\)个模型中选择出一个最优模型。
虽然向前逐步选择在实际中有很好的应用,但是该方法无法保证找到的模型是所有\(2^p\)个模型中最优的。例如,在给定的包含三个变量的数据集中,最优的单变量模型只包括变量\(X_1\),最优的双变量模型包含\(X_2\)与\(X_3\),则通过向前逐步选择方法无法得到双变量最优模型,因为\(M_1\)包含变量\(X_1\),从而\(M_2\)只能包含\(X_1\)及另一变量,\(X_2\)或\(X_3\)。在高维数据中,甚至n>p的情况下,依然可以使用向前逐步选择方法;在这种情况下,可以建立子模型\(M_0,…,M_{n-1}\),因为每个子模型都使用最小二乘法进行拟合,若p\(\ge\)n,结果将是不唯一的。
1.1.2 向后逐步删除
与向前选择不同,向后逐步删除以包含p个变量的全模型为起点,逐次迭代,每次移除一个对模型拟合结果最不利的变量,具体算法不再累述。向后逐步选择方法依然无法保证得到的模型是包含p个预测变量子集的最优模型。该方法需要满足样本量n大于变量个数p(保证全模型可以被拟合)的条件。
在R语言中,通过leaps
包中的regsubsets()
函数可以实现线性回归模型中变量的逐步选择,调用方法是
regsubsets(x=, data=, ...nvmax=8,
method=c("exhaustive", "backward", "forward", "seqrep"),
)
\(x\)可以是矩阵也可以是公式,\(nvmax\)是选择子集数目的上限,通过选择\(method\)中不同的参数可以实现多种子集选择方法,\(backward\)是向后选择,\(forward\)是向前选择。
使用ISLR
包中的\(Hitters\)(棒球)数据集实践逐步选择的方法,实验旨在使用若干个与棒球运动员上一年比赛成绩相关的变量来预测该棒球运动员的\(Salary\)(薪水)。
#install.packages("leaps")#安装软件包
library(leaps)#加载软件包
## Warning: package 'leaps' was built under R version 3.4.4
library(ISLR)
data(Hitters)#调用数据集
names(Hitters)#提取数据集变量名
## [1] "AtBat" "Hits" "HmRun" "Runs" "RBI"
## [6] "Walks" "Years" "CAtBat" "CHits" "CHmRun"
## [11] "CRuns" "CRBI" "CWalks" "League" "Division"
## [16] "PutOuts" "Assists" "Errors" "Salary" "NewLeague"
sum(is.na(Hitters))#计算缺失值个数
## [1] 59
data=na.omit(Hitters)#剔除缺失值
#向前逐步选择
regit.fwd=regsubsets(Salary~.,data=data,nvmax=19,method="forward")
reg.summary=summary(regit.fwd)#汇总模型信息
reg.summary
## Subset selection object
## Call: regsubsets.formula(Salary ~ ., data = data, nvmax = 19, method = "forward")
## 19 Variables (and intercept)
## Forced in Forced out
## AtBat FALSE FALSE
## Hits FALSE FALSE
## HmRun FALSE FALSE
## Runs FALSE FALSE
## RBI FALSE FALSE
## Walks FALSE FALSE
## Years FALSE FALSE
## CAtBat FALSE FALSE
## CHits FALSE FALSE
## CHmRun FALSE FALSE
## CRuns FALSE FALSE
## CRBI FALSE FALSE
## CWalks FALSE FALSE
## LeagueN FALSE FALSE
## DivisionW FALSE FALSE
## PutOuts FALSE FALSE
## Assists FALSE FALSE
## Errors FALSE FALSE
## NewLeagueN FALSE FALSE
## 1 subsets of each size up to 19
## Selection Algorithm: forward
## AtBat Hits HmRun Runs RBI Walks Years CAtBat CHits CHmRun CRuns
## 1 ( 1 ) " " " " " " " " " " " " " " " " " " " " " "
## 2 ( 1 ) " " "*" " " " " " " " " " " " " " " " " " "
## 3 ( 1 ) " " "*" " " " " " " " " " " " " " " " " " "
## 4 ( 1 ) " " "*" " " " " " " " " " " " " " " " " " "
## 5 ( 1 ) "*" "*" " " " " " " " " " " " " " " " " " "
## 6 ( 1 ) "*" "*" " " " " " " "*" " " " " " " " " " "
## 7 ( 1 ) "*" "*" " " " " " " "*" " " " " " " " " " "
## 8 ( 1 ) "*" "*" " " " " " " "*" " " " " " " " " "*"
## 9 ( 1 ) "*" "*" " " " " " " "*" " " "*" " " " " "*"
## 10 ( 1 ) "*" "*" " " " " " " "*" " " "*" " " " " "*"
## 11 ( 1 ) "*" "*" " " " " " " "*" " " "*" " " " " "*"
## 12 ( 1 ) "*" "*" " " "*" " " "*" " " "*" " " " " "*"
## 13 ( 1 ) "*" "*" " " "*" " " "*" " " "*" " " " " "*"
## 14 ( 1 ) "*" "*" "*" "*" " " "*" " " "*" " " " " "*"
## 15 ( 1 ) "*" "*" "*" "*" " " "*" " " "*" "*" " " "*"
## 16 ( 1 ) "*" "*" "*" "*" "*" "*" " " "*" "*" " " "*"
## 17 ( 1 ) "*" "*" "*" "*" "*" "*" " " "*" "*" " " "*"
## 18 ( 1 ) "*" "*" "*" "*" "*" "*" "*" "*" "*" " " "*"
## 19 ( 1 ) "*" "*" "*" "*" "*" "*" "*" "*" "*" "*" "*"
## CRBI CWalks LeagueN DivisionW PutOuts Assists Errors NewLeagueN
## 1 ( 1 ) "*" " " " " " " " " " " " " " "
## 2 ( 1 ) "*" " " " " " " " " " " " " " "
## 3 ( 1 ) "*" " " " " " " "*" " " " " " "
## 4 ( 1 ) "*" " " " " "*" "*" " " " " " "
## 5 ( 1 ) "*" " " " " "*" "*" " " " " " "
## 6 ( 1 ) "*" " " " " "*" "*" " " " " " "
## 7 ( 1 ) "*" "*" " " "*" "*" " " " " " "
## 8 ( 1 ) "*" "*" " " "*" "*" " " " " " "
## 9 ( 1 ) "*" "*" " " "*" "*" " " " " " "
## 10 ( 1 ) "*" "*" " " "*" "*" "*" " " " "
## 11 ( 1 ) "*" "*" "*" "*" "*" "*" " " " "
## 12 ( 1 ) "*" "*" "*" "*" "*" "*" " " " "
## 13 ( 1 ) "*" "*" "*" "*" "*" "*" "*" " "
## 14 ( 1 ) "*" "*" "*" "*" "*" "*" "*" " "
## 15 ( 1 ) "*" "*" "*" "*" "*" "*" "*" " "
## 16 ( 1 ) "*" "*" "*" "*" "*" "*" "*" " "
## 17 ( 1 ) "*" "*" "*" "*" "*" "*" "*" "*"
## 18 ( 1 ) "*" "*" "*" "*" "*" "*" "*" "*"
## 19 ( 1 ) "*" "*" "*" "*" "*" "*" "*" "*"
每一行表示一个模型,序号表示的是模型中所含变量的个数,该模型选择的变量是带星号的变量,比如包含5个变量的向前选择最优模型包含的变量是:AtBat,Hits,CRBI,DivisionW,PutOuts。若是要采取向后选择的方法,只需将\(method\)中的参数改为\(backward\)即可。
接下来画出所有模型的\(RSS\),调整\(R^2\),\(C_p\)及\(BIC\)图像以辅助我们确定最终选择哪个模型。
par(mfrow=c(2,2))#同一页上展示4张图,两行两列
plot(reg.summary$rss,xlab="变量个数",ylab="RSS",type="l")#画残差图
plot(reg.summary$adjr2,xlab="变量个数",ylab="Ajusted Rsq",type="l")#画调整R方图
which.max(reg.summary$adjr2)#找出调整R方最大的点
## [1] 11
points(11,reg.summary$adjr2[11],col="red")#在原图上将调整R方最大的点标红
plot(reg.summary$cp,xlab="变量个数",ylab="Cp",type="l")#画Cp图
which.min(reg.summary$cp)
## [1] 10
points(10,reg.summary$cp[10],col="red")
which.min(reg.summary$bic)
## [1] 6
plot(reg.summary$bic,xlab="变量个数",ylab="BIC",type="l")#画BIC图
points(6,reg.summary$bic[6],col="red")
从返回结果和图中看可以看到,残差在变量个数10之后很小且差异不大,调整\(R^2\)值在变量个数为11时最大,\(C_p\)值在变量个数为10时最小,本着在模型效果差不多时选择更简洁模型的原则,我们选择含有10个变量的模型。至于选择哪10个,向前选择的返回结果中已经告诉我们了。
1.2 Lasso
我们一般通过最小二乘法来估计回归模型系数,而Lasso则是在最小二乘式中加入一个压缩惩罚项,如下式所示\[\sum_{i=1}^n(y_i-\beta_0-\sum_{j=1}^p\beta_jx_{ij})^2+\lambda\sum_{j=1}^p\beta_j^2\]
这个压缩惩罚项当\(\beta_0,…,\beta_p\)接近零时比较小,因此具有将\(\beta_j\)估计值往零的方向进行压缩的作用。调节参数\(\lambda\)的作用是控制惩罚项对回归系数估计的相对影响程度,当\(\lambda=0\)时,惩罚项不起作用,随着\(\lambda\)的增大,压缩惩罚项的影响力增加,会将相关性小的变量前的系数压缩到零,当参数趋于无穷时,会把所有变量系数都压缩为零,因此选择合适的\(\lambda\)值十分重要。
在R语言中,用glmnet
包中的glmnet()
函数来实现Lasso,函数调用方式为
glmnet(x,y,alpha=1,lambda,...)
其中,x是预测变量矩阵,y是相应变量,alpha取1时拟合Lasso,取0时拟合岭回归
#install.packages("glmnet")#安装软件包
library(glmnet)#加载软件包
## Warning: package 'glmnet' was built under R version 3.4.4
## Loading required package: Matrix
## Loading required package: foreach
## Warning: package 'foreach' was built under R version 3.4.4
## Loaded glmnet 2.0-16
grid=10^seq(10,-2,length=100)#lambda取值区间在10^10到10^(-2)之间取
x=model.matrix(data$Salary~.,data)[,-1]#构造回归设计矩阵,该函数不仅能生成与预测变量对应的矩阵,还能自动将定性变量转化为哑变量
y=data$Salary#提取Salary变量为响应变量
lasso.mod=glmnet(x,y,alpha=1,lambda=grid)
plot(lasso.mod)#画系数图像
在图像中,不同颜色的线表示系数值随参数变化的情况,可以看到,随着调节参数选择的不同,某些预测变量的系数会变为0。
接下来就是参数选择的问题,为了尽可能的降低测试误差,统计机器学习为我们提供了一个很好的方法——k折交叉验证(k-fold CV)。这种方法将观测集随机地分为K个大小基本一致的组(折),第一折作为验证集,然后在剩下的k-1折上拟合模型,均方误差由保留折的观测计算得出。重复这个步骤k次,每一次把不同的观测组作为验证集,整个过程会得到k个测试误差的估计,最后对这k个测试误差取平均得到最终的测试误差。现在我们就用这种方法来选择参数。在R语言中,通过cv.glmnet()
函数实现对Lasso的交叉验证
set.seed(1)
cv.out=cv.glmnet(x,y,alpha=1)
plot(cv.out)
首先从图像上可以看到,随着lambda值越来越大,模型均方误差也越来越大,在1-4之间比较小且稳定。接下来我们精确定位最优参数值。
bestlam=cv.out$lambda.min#提取使得均方误差最小的参数值
bestlam#展示最优参数值
## [1] 2.935124
lasso.coef=predict(lasso.mod,type="coefficients",s=bestlam)[1:20,]#提取模型系数值
lasso.coef#展示各项系数
## (Intercept) AtBat Hits HmRun Runs
## 117.3837723 -1.4822814 5.5218995 0.0000000 0.0000000
## RBI Walks Years CAtBat CHits
## 0.0000000 4.6101859 -9.0754521 0.0000000 0.0000000
## CHmRun CRuns CRBI CWalks LeagueN
## 0.4884478 0.6349678 0.3938060 -0.5007016 31.6550343
## DivisionW PutOuts Assists Errors NewLeagueN
## -119.1968930 0.2705311 0.1601517 -1.9317399 0.0000000
可以看到,最优参数值为2.935,在这个参数下,模型有6个变量前的系数被压缩为0,说明Lasso所选择的模型具有13个变量。
2 数值规约
之前讲的属性规约是对变量进行约减,而数据规约还有另一个方面就是对样本量进行约减,这种操作叫做数值规约。数值规约是通过选择替代的、较小的数据来减少数据量,包括有参数方法和无参数方法两类。有参数方法是使用一个模型来评估数据,只需存放参数,而不需要存放实际数据(也就是说把数据样本规约成了一个由参数决定的模型),如回归(线性回归和多元回归)、对数线性模型(近似离散属性集中的多维概率分布)。无参数方法就需要存放实际数据,如直方图、聚类、抽样(采样)。
直方图使用分箱来近似数据分布,是一种流行的数据规约形式。属性A的直方图将A的数据划分为不相交的子集或桶。如果每个桶只代表单个属性值/频率对,则该桶称为单桶。通常,桶表示给定属性的一个连续区间。R中用函数hist()
绘制直方图,用以说明变量取值的分布情况。规约就是合并临近的桶,通常让每个桶代表给定属性的一个连续值域。
聚类技术是将数据记录视为对象,它将对象划分为簇,使一个簇中的对象相互“相似”而与其他簇中的对象“相异”。在数据规约中,用数据的簇替换实际数据,该技术的有效性依赖于簇的定义是否符合数据的分布性质。聚类方法也在聚类一章中有详细介绍。
抽样也是一种数据规约技术,它用比原始数据小得多的随机样本(子集)表示原始数据集。抽样最常用来估计聚集查询的结果,在指定的误差范围内,可以确定估计一个给定函数所需的样本大小。具体的抽样方法在R数据操作一章中讲到。
参数回归,简单线性模型和对数线性模型可以用来近似给定的数据。简单线性模型对数据建模,使之拟合成一条直线。对数线性模型用来描述期望频数与协变量(指与因变量有线性相关并在探讨自变量与因变量关系时通过统计技术加以控制的变量)之间的关系。对数线性模型的形式为\[ln m=\beta_0+\beta_1x_1+…+\beta_kx_k\] 对数线性模型一般用来近似离散的多维概率分布。在一个n元组的集合中,每个元组可以看作是n维空间中的一个点。
3 总结
本章介绍了数据处理的四个任务:数据清洗、数据集成、数据变换和数据规约。数据清洗主要介绍了对缺失值和异常值的处理,处理缺失值的方法分为三类:删除法、替换法、插补法;处理异常值的方法有:直接剔除、盖帽法修正、均值修正、聚类法、视为缺失值等。数据集成是合并多个数据源中的数据,并存放到一个数据存储中的过程,对该部分的介绍从实体识别和冗余属性识别两个方面进行。数据变换介绍了如何从不同的应用角度对已有属性进行函数变换。数据规约从属性规约和数值规约两个方面介绍了如何对数据进行规约,使数据分析的性能和效率得到很大的提高。通过对原始数据进行相应的处理,将为后续分析提供良好的数据基础。
4 参考文献
[1]张良均. R语言数据分析与挖掘实战[M]. 机械工业出版社, 2015.
[2]Gareth James. 统计学习导论基于R应用[M]. 机械工业出版社,2015.