基于R语言的支持向量机实现
数据挖掘一般包含四类算法,即分类、聚类、预测和关联,分类中常用的有Logistic回归、决策树、贝叶斯、支持向量机等算法,本文将针对支持向量机做一个简单的介绍和应用。
支持向量机是数据挖掘中的一项新技术,是借助于最优化方法来解决机器学习问题的新工具,开始成为克服“维度灾难”和过学习等困难的强有力手段。
支持向量机的简介
这里用一个线性分类器来引入支持向量机的原理,下图为线性分类器的一个例子:
从图中可知,线性可分的那条直线即为分类器,在高维中,这条直线称为超平面。很明显A点和W点同属于一类,而B点恰好在分类器上,无法正确判断它属于哪个类别。图中的omiga就为点到线的距离,在分类器中,希望点到线的距离越大越好,越大越能说明分类的可信度越高,正如A点和W点。
如果在高维分类器中,就可以将点到线的距离理解为点到超平面的距离,根据点到面的距离公式:
为了能够求解距离的最大化,即:
可以将图中的式子改写为:
这就将最大化问题变为了求解最小化的问题,这是一个典型的二次规划问题,从而使问题简单化,进一步可以方便的求出参数w和b。
上面所介绍的是基于线性可分的情况,对于现实数据中很大一部分都是线性不可分的,这时就要考虑使用核函数将特征映射到高维中,解决线性不可分问题。如图所示,原始特征是线性不可分的,通过高斯核函数变换后,就可以实现新的线性可分:
R语言用语
支持向量机可通过e1071包中的svm()函数实现,有关该函数的语法如下:
svm(formula, data = NULL, ..., subset,
na.action =na.omit, scale = TRUE)
svm(x, y = NULL, scale = TRUE, type = NULL,
kernel ="radial", degree = 3,
gamma = if (is.vector(x)) 1 else 1 / ncol(x),
coef0 = 0, cost = 1, nu = 0.5,
class.weights = NULL, cachesize = 40,
tolerance = 0.001, epsilon = 0.1,shrinking = TRUE,
cross = 0, probability = FALSE, fitted = TRUE,
..., subset, na.action = na.omit)
formula指定参与分析的变量公式,类似于y~x1+x2;
data指定分析的数据集;
subset为一个索引向量,指定分析的样本数据;
na.action针对缺失值的处理方法,默认会删除缺失值所在的行;
scale逻辑参数,是否标准化变量,默认标准化处理;
x可以是矩阵,可以是向量,也可以是稀疏矩阵;
y为分类变量;
type指定建模的类别,支持向量机通常用于分类、回归和异常值检测,默认情况下,svm模型根据因变量y是否为因子,type选择C-classification或eps-regression。
kernel指定建模过程中使用的核函数,目的在于解决支持向量机线性不可分问题。有四类核函数可选,即线性核函数、多项式核函数、径向基核函数(高斯核函数)和神经网络核函数。研究人员发现,识别率最高,性能最好的是径向基核函数(默认的kernel值),其次是多项式核函数,最差的是神经网络核函数;
degree用于多项式核函数的参数,默认为3;
gamma用于除线性核函数之外的所有核函数参数,默认为1;
coef0用于多项式核函数和神经网络核函数的参数,默认为0;
nu用于nu-classification、nu-regression和one-classification回归类型中的参数
class.weights指定类权重;
cachesize默认缓存大小为40M;
cross可为训练集数据指定k重交叉验证;
probability逻辑参数,指定模型是否生成各类的概率预测,默认不产生概率值;
fitted逻辑参数,是否将分类结果包含在模型中,默认生成拟合值。
应用
对于分类问题,支持向量机的type参数有C-classification、nu-classification和one-classification三种选项,核函数kernel参数有linear、polynomial、radial和sigmoid四种选项,为了综合比较这12种组合的模型效果,编辑脚本如下:
library(e1071)
SVM <- function(x,y){
type <- c('C-classification','nu-classification','one-classification')
kernel <- c('linear','polynomial','radial','sigmoid')
#用于存放12种组合的预测结果
pred <- array(0, dim=c(nrow(x),3,4))
#用于存放预测错误数
errors <- matrix(0,3,4)
dimnames(errors) <- list(type, kernel)
for(i in 1:3){
for(j in 1:4){
pred[,i,j] <- predict(object = svm(x, y, type = type[i], kernel = kernel[j]), newdata = x)
if(i > 2) errors[i,j] <- sum(pred[,i,j] != 1)
else errors[i,j] <- sum(pred[,i,j] != as.integer(y))
}
}
return(errors)
}
有关该函数需要注意的几点:
1)x为分析的自变量数据框或矩阵;
2)y为分析的因变量向量,必须为因子;
3)nu-classification、one-classification与C-classification的预测返回值不同,所以在统计错误预测时分if条进行两种处理。
这里以R中自带的iris数据集为例,看看这12种组合在该数据集中的优劣:
x <- iris[,1:4]
y <- iris[,5]
SVM(x = x, y = y)
根据以上结果,type='C-classification',kernel='radial'的返回错判量最小,故可以考虑这种组合对iris进行分类。
model <- svm(x = iris[,1:4], y = iris[,5], type = 'C-classification', kernel = 'radial')
pred <- predict(object = model, newdata = iris[,1:4])
Freq <- table(iris[,5], pred)
Freq
accuracy <- sum(diag(Freq))/sum(Freq)
accuracy
正确分类率达到97.3%,但任然发现有4个样本被误判,为了进一步提高分类效果,可以考虑使用svm函数中的class.weights参数为不同的类指定权重,一般规则是:某个类与其他类存在明显差异时,考虑给予较小的权重,某些类之间差异较小时,考虑给予较大的权重。
library(ggplot2)
p <- ggplot(data = iris)
p <- p + geom_point(mapping = aes(x = Petal.Length, y = Petal.Width, colour = Species))
p
从图中明显得出setosa与versicolor、virginica存在明显差异,故考虑赋给setosa的权重小一点,而赋给versioolor和virginica的权重大一些。
#给versicolor和virginica分布赋予200和500的权重,而setosa只赋予1的权重
weights <- c(1,200,500)
names(weights) <- c('setosa','versicolor','virginica')
model2 <- svm(x = iris[,1:4], y = iris[,5], type = 'C-classification', kernel = 'radial', class.weights = weights)
pred2 <- predict(object = model2, newdata = iris[,1:4])
Freq2 <- table(iris[,5], pred2)
Freq2
accuracy2 <- sum(diag(Freq2))/sum(Freq2)
accuracy2
参考资料:
数据挖掘:R语言实战
http://www.chinakdd.com/article-W82k0g2822JE712.html
http://blog.csdn.net/passball/article/details/7661887/
总结:文中涉及到的R包和函数
e1071包
svm()
predict()
ggplot2包
ggplot()
geom_point()