天天看點

R 支援向量機②

介紹

支援向量機是一個相對較新和較先進的機器學習技術,最初提出是為了解決二類分類問題,現在被廣泛用于解決多類非線性分類問題和回歸問題。其流行歸功于兩個方面,一個方面,可以輸出比較準确的預測結果;另一方面,模型基于比較優雅的數學理論。

SVM旨在在多元空間找到一個能将全部樣本單元分成兩類的最優平面,這一平面應使兩類中距離最近的點的間距最大。在間距邊界上的點稱為支援向量,分割的超平面位于間距中間。SVM函數通過核函數将資料投影到高維,使其在高維線性可分。

由于方差較大的預測變量通常對SVM影響更大,svm()函數預設在生成模型前對每個變量标準化,使其标準化值為0,标準差為1。

工作原理

假設你的資料點分為兩類,支援向量機試圖尋找最優的一條線(超平面),使得離這條線最近的點與其他類中的點的距離最大。有些時候,一個類的邊界上的點可能越過超平面落在了錯誤的一邊,或者和超平面重合,這種情況下,需要将這些點的權重降低,以減小它們的重要性。

這種情況下,“支援向量”就是那些落在分離超平面邊緣的資料點形成的線。

  • 無法确定分類線(線性超平面)時

    此時可以将資料點投影到一個高維空間,在高維空間中它們可能就變得線性可分了。它會将問題作為一個帶限制的最優化問題來定義和解決,其目的是為了最大化兩個類的邊界之間的距離。

  • 資料點多于兩個類時

    此時支援向量機仍将問題看做一個二進制分類問題,但這次會有多個支援向量機用來兩兩區分每一個類,直到所有的類之間都有差別。

線性支援向量機

  • 傳遞給函數svm()的關鍵參數是kernel、cost和gamma。
  • Kernel指的是支援向量機的類型,它可能是線性SVM、多項式SVM、徑向SVM或Sigmoid SVM。
  • Cost是違反限制時的成本函數,gamma越大,通常導緻支援向量越多。我們也可将gamma看作控制訓練樣本“到達範圍”的參數,即gamma越大意味着訓練樣本到達範圍越廣,而越小則意味着到達範圍越窄。gamma是除線性SVM外其餘所有SVM都使用的一個參數。
  • svm()函數預設gamma為預測變量個數的倒數。還有一個類型參數,用于指定該模型是用于回歸、分類還是異常檢測。但是這個參數不需要顯式地設定,因為支援向量機會基于響應變量的類别自動檢測這個參數,響應變量的類别可能是一個因子或一個連續變量。是以對于分類問題,一定要把你的響應變量作為一個因子。
> # linear SVM
> svmfit <- svm(response ~ ., data = inputData, kernel = "linear", 
+               cost = 10, scale = FALSE) # linear svm, scaling turned OFF
> print(svmfit)

Call:
svm(formula = response ~ ., data = inputData, kernel = "linear", 
    cost = 10, scale = FALSE)


Parameters:
   SVM-Type:  C-classification 
 SVM-Kernel:  linear 
       cost:  10 
      gamma:  0.5 

Number of Support Vectors:  79

> plot(svmfit, inputData)
> compareTable <- table (inputData$response, predict(svmfit))  # tabulate
> mean(inputData$response != predict(svmfit)) # 19.44% misclassification error
[1] 0.1944444
           
R 支援向量機②
  • 通過breast資料示範支援向量機
rm(list=ls())
setwd("E:\\Rwork")


loc <- "http://archive.ics.uci.edu/ml/machine-learning-databases/"
ds <- "breast-cancer-wisconsin/breast-cancer-wisconsin.data"
url <- paste(loc, ds, sep="")
breast <- read.table(url, sep=",", header=FALSE, na.strings="?")
names(breast) <- c("ID", "clumpThickness", "sizeUniformity",
                   "shapeUniformity", "maginalAdhesion",
                   "singleEpithelialCellSize", "bareNuclei",
                   "blandChromatin", "normalNucleoli", "mitosis", "class")

write.csv(breast,"breast.csv")
df <- breast[-1]
df$class <- factor(df$class, levels=c(2,4),
                   labels=c("benign", "malignant"))
set.seed(1234)
index <- sample(nrow(df), 0.7*nrow(df))
df.train <- df[index,]
df.validate <- df[-index,]
table(df.train$class)
table(df.validate$class)


# linear SVM
svmfit <- svm(class ~ ., data = df.train, kernel = "linear", 
              cost = 10, scale = FALSE) # linear svm, scaling turned OFF
print(svmfit)


svm.pred <- predict(svmfit, na.omit(df.validate))
svm.perf <- table(na.omit(df.validate)$class,
                  svm.pred, dnn=c("Actual", "Predicted"))

svm.perf 




# radial SVM
svmfit <- svm(response ~ ., data = inputData, 
              kernel = "radial", cost = 10, 
              scale = FALSE) # radial svm, scaling turned OFF
print(svmfit)

svm.pred <- predict(svmfit, na.omit(df.validate))
svm.perf <- table(na.omit(df.validate)$class,
                  svm.pred, dnn=c("Actual", "Predicted"))
svm.perf 





### Tuning
# Prepare training and test data
set.seed(1234) # for reproducing results
rowIndices <- 1 : nrow(breast) # prepare row indices
sampleSize <- 0.8 * length(rowIndices) # training sample size
trainingRows <- sample (rowIndices, sampleSize) # random sampling
trainingData <- breast[trainingRows, ] # training data
testData <- breast[-trainingRows, ] # test data
tuned <- tune.svm(class~., data = trainingData,
                  gamma = 10^(-6:-1), cost = 10^(1:2)) # tune
summary (tuned) # to select best gamma and cost


svmfit <- svm (class ~ ., 
               data = trainingData, kernel = "radial",
               cost = 10, gamma=0.01, 
               scale = FALSE)
# radial svm, scaling turned OFF
print(svmfit)
svm.perf <- table(na.omit(df.validate)$class,
                  svm.pred, dnn=c("Actual", "Predicted"))
svm.perf 
···