基于R语言的判别分析
判别分析又称“分辨法”,是在分类确定的条件下,根据某一研究对象的各种特征值判别其类型归属问题的一种多变量统计分析方法。常见的判别分析方法有距离判别法、贝叶斯判别法和Fisher判别法。
距离判别法
基于距离的数据挖掘算法有很多,比如聚类算法中的层次聚类法、k-均值法、k-中心法等,这里的判别分析实际上也是分类算法中的一种。常用的距离有欧式距离、马氏距离、曼哈顿距离等(更多的距离方法可参见博文:http://www.cnblogs.com/wentingtu/archive/2012/05/03/2479919.html),这里就介绍前两种距离:
欧式距离
但该距离法在计算多个总体之间的距离时并不考虑方差的影响。借《统计建模与R语言》书中的内容,说明该距离的缺陷:
假设图中的两个总体均服从正态分布,且X1~N(0,1),X2~N(4,4)。那么点A(1.66,0)距离总体X1和X2哪个更近呢?表面上看A点距离总体X1的均值最近,但实际上考虑方差后我们发现A点距离总体X2更近,因为:A点距总体X1的中心点为1.66个标准差,而距总体X2的中心点为1.17((4-1.66)/2=1.17)个标准差。所以A点距离总体X2更近。
马氏距离
该距离方法正好解决了欧式距离在这方面的缺点,其距离公式为:
其中公式的中间项就为总体之间的协方差阵。
根据距离判别法的准则,将新样本距离最近的类判为该类,即:
有关距离比较的判别函数理论部分可参考《统计建模与R语言》这本书,该书的作者还写了距离判别法、贝叶斯判别法和Fisher判别法的自定义函数(推荐读者看看该书中的第8章内容)。
有关距离判别法,K最邻近算法(KNN)是使用最为广泛的。为了说明K最邻近算法,结合使用下方的图做一个解释:
图中实心点为待判样本点,空心点为已知类别的点。K最邻近算法中的K是分析人员要给定的值,如图中给定K为5,则在实心点附近寻找最近的5个点(这里的最近就可以用到上文中距离的计算),接下来根据这5个点来判断待判样本点属于哪一类,判定规则是:5个点中属于哪个类最多,则待判样本点就属于哪个类。很明显图中最上方的实心点属于三角形类,左边实心点属于圆形类,右边实心点属于正方形类。
关于K最邻近算法的实现可以使用class包中的knn()函数。knn()函数的语法和参数如下:
knn(train, test, cl, k = 1, l = 0, prob = FALSE, use.all = TRUE)
train指定训练样本集;
test指定测试样本集;
cl指定训练样本集中分类变量;
k指定最邻近的k个已知分类样本点,默认为1;
l指定待判样本点属于某类的最少已知分类样本数,默认为0;
prob设为TRUE时,可以得到待判样本点属于某类的概率,默认为FALSE;
use.all控制节点的处理办法,即如果有多个第K近的点与待判样本点的距离相等,默认情况下将这些点都纳入判别样本点,当该参数设为FALSE时,则随机挑选一个样本点作为第K近的判别点。
距离判别法的应用
#通过抽样建立训练样本和测试样本
index <- sample(2,size = nrow(iris),replace = TRUE,
prob = c(0.75,0.25))
train <- iris[index == 1,]
test <- iris[index == 2,]
#加载R包并使用KNN算法
library(class)
res1 <- knn(train = train[,1:3], test = test[,1:3],
cl = as.factor(train$Species),k = 5)
#生成实际与预判交叉表和预判精度
table(test$Species,res1)
sum(diag(table(test$Species,res1)))/sum(table(test$Species,res1))
还有一种距离判别法是基于K最邻近算法基础上的扩充,该算法为加权的K最邻近算法,有关该算法的实现可以参考kknn包中的kknn()函数。
贝叶斯判别法
贝叶斯判别法的前提是分析人员已经对所分析的数据有所了解(比如数据服从什么分别,各个类别的先验概率等),根据各个类别的先验概率求得新样本属于某类的后验概率。该算法应用到经典的贝叶斯公式,该公式为:
贝叶斯判别法的思想
设有两个总体,它们的先验概率分别为q1、q2,各总体的密度函数为f1(x)、f2(x),在观测到一个样本x的情况下,可用贝叶斯公式计算它来自第k个总体的后验概率为:
判别规则
对于待判样本x,计算x属于所有类别的后验概率,如果属于某类的后验概率最大,则将该待判样本划分到该类中。
关于贝叶斯判别法的实现可以使用klaR包中的NaiveBayes()函数。NaiveBayes()函数的语法和参数如下:
NaiveBayes(formula, data, ..., subset, na.action = na.pass)
NaiveBayes(x, grouping, prior, usekernel = FALSE, fL = 0, ...)
formula指定参与模型计算的变量,以公式形式给出,类似于y=x1+x2+x3;
data用于指定需要分析的数据对象;
na.action指定缺失值的处理方法,默认情况下不将缺失值纳入模型计算,也不会发生报错信息,当设为“na.omit”时则会删除含有缺失值的样本;
x指定需要处理的数据,可以是数据框形式,也可以是矩阵形式;
grouping为每个观测样本指定所属类别;
prior可为各个类别指定先验概率,默认情况下用各个类别的样本比例作为先验概率;
usekernel指定密度估计的方法(在无法判断数据的分布时,采用密度密度估计方法),默认情况下使用标准的密度估计,设为TRUE时,则使用核密度估计方法;
fL指定是否进行拉普拉斯修正,默认情况下不对数据进行修正,当数据量较小时,可以设置该参数为1,即进行拉普拉斯修正。
朴素贝叶斯判别法的应用
#通过抽样建立训练样本和测试样本
index <- sample(2,size = nrow(iris),replace = TRUE,
prob = c(0.75,0.25))
train <- iris[index == 1,]
test <- iris[index == 2,]
#加载R包并使用朴素贝叶斯算法
library(klaR)
res2 <- NaiveBayes(Species ~ ., data = train)
pre <- predict(res2, newdata = test[,1:4])
#生成实际与预判交叉表和预判精度
table(test$Species,pre$class)
sum(diag(table(test$Species,pre$class)))/sum(table(test$Species,pre$class))
Fisher判别法
Fisher判别法是按类内方差尽量小,类间方差尽量大的准则来求判别函数,该判别法的基本思想是:将高维空间的点向低维空间投影。为了说明,这里参考《数据挖掘:R语言实战》中的图来解释Fisher判别法的思想:
图中显示,将样本空间中的点投影到“原桌标轴”后发现存在一些重叠的点,这样就无法将这些重叠的点有效的划分到个各类中。
如果将样本空间中的点投影到某个线性函数中,即上图中的“投影轴”,这样就不会出现重叠样本的情况,这里的线性函数可以表示成:
Fisher判别法的重点就是选择适当的“投影轴”,对于线性判别来说,可以先将样本点投影到一维空间(u(x)=a1x1),如果划分的效果不理想,可以考虑投影到二维空间(u(x)=a1x1+a2x2),以此类推。对于非线性判别来说,可以使用二次型判别函数,可以将样本点投影到若干种二次曲面中,实现理想的判别效果。
往往实际应用中,复杂的数据无法使用线性判别函数得到理想的判别效果,就必须使用类似于二次判别函数的非线性分类方法。
关于Fisher线性判别和二次判别方法的实现可以使用MASS包中的lda()函数和qda()函数。lda()函数和qda()函数的语法和参数如下:
lda(formula, data, ..., subset, na.action)
lda(x, grouping, prior = proportions,
tol = 1.0e-4,method, CV = FALSE, nu, ...)
lda(x, grouping, ..., subset, na.action)
qda(formula, data, ..., subset, na.action)
qda(x, grouping, prior = proportions,
method, CV = FALSE, nu, ...)
qda(x, grouping, ..., subset, na.action)
formula指定参与模型计算的变量,以公式形式给出,类似于y=x1+x2+x3;
data用于指定需要分析的数据对象;
na.action指定缺失值的处理方法,默认情况下,缺失值的存在使算法无法运行,当设置为“na.omit”时则会删除含有缺失值的样本;
x指定需要处理的数据,可以是数据框形式,也可以是矩阵形式;
grouping为每个观测样本指定所属类别;
prior可为各个类别指定先验概率,默认情况下用各个类别的样本比例作为先验概率;
method指定计算均值和方差的方法,默认情况下使用最大似然估计,还可以使用mve法和稳健估计法(基于t分布);
CV是否进行交叉验证,默认情况下不进行交叉验证。
Fisher判别法的应用
#通过抽样建立训练样本和测试样本
index <- sample(2,size = nrow(iris),
replace = TRUE, prob = c(0.75,0.25))
train <- iris[index == 1,]
test <- iris[index == 2,]
#加载R包并使用Fisher线性判别法
library(MASS)
lda_res3 <- lda(Species~., data = train)
lda_pre3 <- predict(lda_res3, newdata = test[,1:4])
#生成实际与预判交叉表和预判精度
table(test$Species,lda_pre3$class)
sum(diag(table(test$Species,lda_pre3$class)))/sum(table(test$Species,lda_pre3$class))
#使用Fisher二次判别法
lda_res4 <- qda(Species~., data = train)
lda_pre4 <- predict(lda_res3, newdata = test[,1:4])
#生成实际与预判交叉表和预判精度
table(test$Species,lda_pre4$class)
sum(diag(table(test$Species,lda_pre4$class)))/sum(table(test$Species,lda_pre4$class))
上图中发现线性判别法和非线性的二次判别法得到的结果一致,说明线性判别法就能够很好的将数据的类别划分出来了,且准确率达到98%。
有关判别分析中的距离判别法、贝叶斯判别法和Fisher判别法就讲解到这里,在实际的应用中可以考虑多种方法的比较和使用,根据实际的业务情况选择合适的判别方法。
参考资料:
统计建模与R语言
数据挖掘:R语言实战
http://www.cnblogs.com/wentingtu/archive/2012/05/03/2479919.html
总结:文中涉及到的R包和函数
stats包
sample()
table()
sum()
diag()
class包
knn()
kknn包
kknn()
klaR包
NaiveBayes()
predict()
MASS包
dla()
qla()
predict()