Learn R | SVM of Data Mining(五)

回顧在前面的四篇文章中,通過建立支持向量、函數與幾何間隔、最大間隔超平面等概念,並使用拉格朗日對偶理論、向量內積與核函數、SMO高效優化演算法等方法,我們依次學習了線性可分SVM(硬間隔)、非線性可分SVM和近似線性可分SVM(軟間隔)。

至此,SVM演算法的數學推導就暫時告一段落了。但SVM演算法其基本原理及背後所蘊含的數學知識確是博大精深,雖然用了四篇文章來推導學習,但自我感覺還是淺嘗輒止,仍然有待於進一步的細究,所以之後如果有新的思考與理解,也會更新補充在這個系列的文章中。而今天主要學習的是SVM演算法的R實現。

在SVM的眾多packages中,最著名的當屬台灣大學林智仁老師開發的LIBSVM了,LIBSVM的官網(LIBSVM -- A Library for Support Vector Machines)中提供了面向不同編程語言使用SVM演算法的interface,其中面向R語言的介面,正是e1071包。

如果之前你閱讀過專欄中機器學習文章的話,想必對這個包並不陌生。在文章Learn R | Naive Bayes of Data Mining中,我們就是使用e1071包的naiveBayes()函數來運行樸素貝葉斯分類演算法,而支持向量機演算法則使用該包的svm()函數來實現。

> library(e1071)n

# svm函數的基本語法及參數解釋n> svm(formula, data = NULL, ..., subset, na.action =na.omit, scale = TRUE)n# formula:指定參與分析的變數公式n# subset:為索引向量,指定分析的樣本數據n# na.action:針對缺失值的處理方法,默認會刪除缺失值所在的行n# scale:邏輯參數,是否標準化變數,默認標準化處理n

> svm(x, y = NULL, scale = TRUE, type = NULL, kernel ="radial", degree = 3,n+ gamma = if (is.vector(x)) 1 else 1 / ncol(x),coef0 = 0, cost = 1, nu = 0.5,n+ class.weights = NULL, cachesize = 40, tolerance = 0.001, epsilon = 0.1,n+ shrinking = TRUE, cross = 0, probability = FALSE, fitted = TRUE,...,subset,n+ na.action = na.omit)n# x:可以是矩陣,可以是向量,也可以是稀疏矩陣n# y:分類變數n# type:指定建模的類別,支持向量機通常用於分類、回歸和異常值檢測,默認情況下,svm模型根據因變數y是否為因子,type選擇C-classification或eps-regressionn# kernel:指定建模過程中使用的核函數,目的在於解決支持向量機線性不可分問題。函數中有四類核函數可選,即線性核函數、多項式核函數、高斯核函數和神經網路核函數n# degree:用於多項式核函數的參數,默認為3n# gamma:用於除線性核函數之外的所有核函數參數,默認為1n# coef0:用於多項式核函數和神經網路核函數的參數,默認為0n# nu:用於nu-classification、nu-regression和one-classification回歸類型中的參數n# class.weights:指定類權重n# cachesize:默認緩存大小為40Mn# cross:可為訓練集數據指定k重交叉驗證n# probability:邏輯參數,指定模型是否生成各類的概率預測,默認不產生概率值n# fitted:邏輯參數,是否將分類結果包含在模型中,默認生成擬合值n

接下來進行兩個實際案例的SVM應用,原始數據分別是MASS包中的cats數據集與R中自帶的經典的iris數據集。

一、Cats數據集

MASS包中的cats數據集共包含三個變數,其中變數Sex表示貓的性別(ForM),Bwt表示貓的體重(單位:kg),Hwt表示貓的心臟重量(單位:g)。我們的目的在於藉助SVM演算法通過Bwt和Hwt這兩個變數對貓進行性別分類。

# 載入包並查看基本信息n> library(MASS)n> head(cats)n Sex Bwt Hwtn1 F 2.0 7.0n2 F 2.0 7.4n3 F 2.0 9.5n4 F 2.1 7.2n5 F 2.1 7.3n6 F 2.1 7.6n

# 分別選取訓練樣本(70%)和測試樣本(30%)n> index <- sample(2,nrow(cats),replace = TRUE,prob=c(0.7,0.3))n> traindata <- cats[index==1,]n> testdata <- cats[index==2,]n

# 構建模型n> cats_svm_model <- svm(Sex~.,data=traindata)n> cats_svm_modelnnCall:nsvm(formula = Sex ~ ., data = traindata)nnnParameters:n SVM-Type: C-classification n SVM-Kernel: radial n cost: 1 n gamma: 0.5 nnNumber of Support Vectors: 60n

# 查看訓練樣本的預測情況n> cats_svm_model_pred_1 <- predict(cats_svm_model,traindata[,-1])n> cats_table_1 <- table(pred=cats_svm_model_pred_1,true=traindata[,1])n truenpred F Mn F 19 9n M 10 55n> accuracy_1 <- sum(diag(cats_table_1))/sum(cats_table_1)n> accuracy_1n[1] 0.7956989n

# 使用建立好的模型進行預測並查看測試樣本的預測情況n> cats_svm_model_pred_2 <- predict(cats_svm_model,testdata[,-1])n> cats_table_2 <- table(pred=cats_svm_model_pred_2,true=testdata[,1])n> cats_table_2n truenpred F Mn F 14 5n M 4 28n> accuracy_2 <- sum(diag(cats_table_2))/sum(cats_table_2)n> accuracy_2n[1] 0.8235294n

# 預測結果的可視化展示n> plot(cats_svm_model,testdata)n

這就是R語言中SVM演算法的一個簡單應用,生成模型並用於預測。需要注意的是,在這個案例中,我們在參數選擇上沒有進行自定義調整,基本使用了函數的默認值,而只有結合數據本身的特徵來選取最合適的參數,才能讓模型的預測精度有所提升。

二、iris數據集

首先,對於分類問題而言,svm()han函數中的type參數有C-classification、nu-classification和one-classification三種選項,核函數kernel參數有linear、polynomial、radial和sigmoid四種選項,為了綜合比較這12種組合的模型效果,建立一個自編函數(參考自劉順祥老師的文章基於R語言的支持向量機實現):

> svm_test <- function(x,y){n + type <- c(C-classification,nu-classification,one-classification)n + kernel <- c(linear,polynomial,radial,sigmoid)n + pred <- array(0, dim=c(nrow(x),3,4))n + errors <- matrix(0,3,4)n + dimnames(errors) <- list(type, kernel)n + for(i in 1:3){n + for(j in 1:4){n + pred[,i,j] <- predict(object = svm(x, y, type = type[i], kernel = kernel[j]), newdata = x)n + if(i > 2) errors[i,j] <- sum(pred[,i,j] != 1)n + else errors[i,j] <- sum(pred[,i,j] != as.integer(y))n + }n + }n + return(errors)n + }n

查看這12種組合在iris數據集中的優劣表現:

> iris_x <- iris[,1:4]n> iris_y <- iris[,5]n> svm_test(x=iris_x,y=iris_y)n linear polynomial radial sigmoidnC-classification 5 7 4 17nnu-classification 5 14 5 12none-classification 102 75 76 75n

根據以上結果,type=C-classificationkernel=radial的返回錯判量最小,故可以考慮這種組合對iris進行分類。

> iris_model <- svm(x=iris[,1:4],y=iris[,5],type = C-classification, n+ kernel = radial)n> iris_pred <- predict(object = iris_model, newdata = iris[,1:4])n> iris_Freq <- table(iris[,5], iris_pred)n> iris_Freqn iris_predn setosa versicolor virginican setosa 50 0 0n versicolor 0 48 2n virginica 0 2 48n> iris_accuracy <- sum(diag(iris_Freq))/sum(iris_Freq)n> iris_accuracyn[1] 0.9733333n

這樣我們看到,正確分類率達到了97.3%,4個樣本被誤判。為了進一步提高分類效果,我們可以使用tune.svm()函數來尋找svm()函數的最優參數。

> tune.svm(Species ~., data =iris, gamma = 10^(-100:-1), cost = 10^(0:3))nnParameter tuning of 『svm』:nn- sampling method: 10-fold cross validation nn- best parameters:n gamma costn 0.1 10nn- best performance: 0.04 n

結果顯示,當cost為10,gamma為0.1時產生最小的錯誤率。利用這些參數繼續訓練演算法:

> iris_model_2 <- svm(x=iris[,1:4],y=iris[,5],type = C-classification, kernel = radial,gamma = 0.1,cost=10)n> iris_pred_2 <- predict(object = iris_model_2, newdata = iris[,1:4])n> iris_Freq_2 <- table(iris[,5], iris_pred_2)n> iris_Freq_2n iris_pred_2n setosa versicolor virginican setosa 50 0 0n versicolor 0 47 3n virginica 0 0 50n> iris_accuracy_2 <- sum(diag(iris_Freq_2))/sum(iris_Freq_2)n> iris_accuracy_2n[1] 0.98n

接著,使用svm()函數中的class.weight參數為不同的類指定權重。

一般規則:某個類與其他類存在明顯差異時,考慮給予較小的權重;某些類之間差異較小時,考慮給予較大的權重。

觀察iris數據集中三類數據

> library(rCharts)n> nPlot(Petal.Length~Petal.Width,group=Species,data=iris,n+ type=scatterChart)n

從圖中明顯可以看到,setosaversicolor、virginica存在明顯差異,故考慮賦給setosa的權重小一點,而賦給versioolor和virginica的權重大一些。

> weights <- c(1,200,500)n> names(weights) <- c(setosa,versicolor,virginica)n

> iris_model_3 <- svm(x=iris[,1:4],y=iris[,5],type = C-classification, kernel = radial,gamma = 0.1,cost=10,class.weights = weights)n> iris_pred_3 <- predict(object = iris_model_3, newdata = iris[,1:4])n> iris_Freq_3 <- table(iris[,5], iris_pred_3)n> iris_Freq_3n iris_pred_3n setosa versicolor virginican setosa 50 0 0n versicolor 0 49 1n virginica 0 0 50n> iris_accuracy_3 <- sum(diag(iris_Freq_3))/sum(iris_Freq_3)n> iris_accuracy_3n[1] 0.9933333n

這樣,經過層層優化,我們模型的誤判減小到1個,分類正確率提高到99.3%。

需要注意的是,在本案例中,我們依次對svm()函數中的type、kernel、cost、gamma和class.weights五個參數進行了最優化探索,從而得到了非常理想的結果。但並不意味這適用於任何數據集,還是那句話,「具體問題具體分析」,只有從數據本身的特性出發,選取合適的方法進行分類判別,才能最大程度確保最終結果的精確度與可信度。

除了e1071包以外,kernlab包同樣也可進行SVM演算法的R實現,這裡不再詳細介紹,有興趣的讀者可自行查閱相關學習資料。

References:

  1. Package 『e1071』

  2. 基於R語言的支持向量機實現

  3. SVM example with Iris Data in R

  4. Data Mining Algorithms In R/Classification/SVM

  5. R上的LIBSVM Package — e1071 [入門篇]

  6. R上的LIBSVM Package — e1071 [參數篇]
  7. 支持向量機在R語言中的實現和使用

  8. The R interface to libsvm is in package e1071

推薦閱讀:

快訊| RStudio Connect 發布
深入分析PE可執行文件是如何進行加殼和數據混淆的
踏潮 BI 學習大綱
運營幹貨 | 「精細化運營」無從下手?那看看這張表吧!

TAG:R编程语言 | 数据挖掘 | 机器学习 |