美文网首页数据科学与R语言R语言作业机器学习
43-R语言机器学习:K最近邻与支持向量机

43-R语言机器学习:K最近邻与支持向量机

作者: wonphen | 来源:发表于2020-03-09 09:58 被阅读0次

    《精通机器学习:基于R 第二版》学习笔记

    1、前文回顾

    前面学习了逻辑斯蒂回归,它被用来预测一个观测属于某个响应变量分类的概率——我们称之为分类问题。逻辑斯蒂回归只是分类方法的开始,还可以使用很多其他方法改善预测质量。
    K最近邻(KNN)与支持向量机(SVM)要比我们之前讨论的那些技术复杂一些,因为放弃了线性假设。也就是说,不再必须使用特征的线性组合来定义决策边界。这样不一定能得到更好的预测结果,而且向业务伙伴解释模型也会有一点问题,计算效率也更低。

    2、K最近邻

    一般用特征的内积(点积)表示核函数,用 xi 和 xj 代表向量, γ 和 c 为参数,常用的核函数如下所示:
     线性核函数: K(xi , xj) = xi · xj,无需转换
     多项式核函数: K(xi , xj) = (γxi · xj + c) d , d 为多项式的次数
     径向基核函数: K(xi , xj) = e( -γ | xi - xj | 2 )
     sigmod 核函数: K(xi , xj) = tanh(γxi · xj + c)

    2.1 数据理解和数据准备

    > library(pacman)
    > p_load(MASS)
    > str(Pima.tr)
    
    ## 'data.frame':    200 obs. of  8 variables:
    ##  $ npreg: int  5 7 5 0 0 5 3 1 3 2 ...
    ##  $ glu  : int  86 195 77 165 107 97 83 193 142 128 ...
    ##  $ bp   : int  68 70 82 76 60 76 58 50 80 78 ...
    ##  $ skin : int  28 33 41 43 25 27 31 16 15 37 ...
    ##  $ bmi  : num  30.2 25.1 35.8 47.9 26.4 35.6 34.3 25.9 32.4 43.3 ...
    ##  $ ped  : num  0.364 0.163 0.156 0.259 0.133 ...
    ##  $ age  : int  24 55 35 26 23 52 25 24 63 31 ...
    ##  $ type : Factor w/ 2 levels "No","Yes": 1 2 1 1 1 2 1 1 1 2 ...
    
    > str(Pima.te)
    
    ## 'data.frame':    332 obs. of  8 variables:
    ##  $ npreg: int  6 1 1 3 2 5 0 1 3 9 ...
    ##  $ glu  : int  148 85 89 78 197 166 118 103 126 119 ...
    ##  $ bp   : int  72 66 66 50 70 72 84 30 88 80 ...
    ##  $ skin : int  35 29 23 32 45 19 47 38 41 35 ...
    ##  $ bmi  : num  33.6 26.6 28.1 31 30.5 25.8 45.8 43.3 39.3 29 ...
    ##  $ ped  : num  0.627 0.351 0.167 0.248 0.158 0.587 0.551 0.183 0.704 0.263 ...
    ##  $ age  : int  50 31 21 26 53 51 31 33 27 29 ...
    ##  $ type : Factor w/ 2 levels "No","Yes": 2 1 1 2 2 2 2 1 1 2 ...
    
    > pima <- rbind(Pima.tr, Pima.te)
    > str(pima)
    
    ## 'data.frame':    532 obs. of  8 variables:
    ##  $ npreg: int  5 7 5 0 0 5 3 1 3 2 ...
    ##  $ glu  : int  86 195 77 165 107 97 83 193 142 128 ...
    ##  $ bp   : int  68 70 82 76 60 76 58 50 80 78 ...
    ##  $ skin : int  28 33 41 43 25 27 31 16 15 37 ...
    ##  $ bmi  : num  30.2 25.1 35.8 47.9 26.4 35.6 34.3 25.9 32.4 43.3 ...
    ##  $ ped  : num  0.364 0.163 0.156 0.259 0.133 ...
    ##  $ age  : int  24 55 35 26 23 52 25 24 63 31 ...
    ##  $ type : Factor w/ 2 levels "No","Yes": 1 2 1 1 1 2 1 1 1 2 ...
    

    数据集包含了 532 位女性患者的信息,存储在两个数据框中。数据集变量如下。
     npreg :怀孕次数
     glu :血糖浓度,由口服葡萄糖耐量测试给出
     bp :舒张压(单位为mm Hg)
     skin :三头肌皮褶厚度(单位为mm)
     bmi :身体质量指数
     ped :糖尿病家族影响因素
     age :年龄
     type :是否患有糖尿病(是 / 否)

    > p_load(class, kknn, caret, reshape2, ggplot2, dplyr)
    > 
    > # 使用箱线图进行探索性数据分析
    > pima.melt <- melt(pima, id.vars = "type")
    > head(pima.melt)
    
    ##   type variable value
    ## 1   No    npreg     5
    ## 2  Yes    npreg     7
    ## 3   No    npreg     5
    ## 4   No    npreg     0
    ## 5   No    npreg     0
    ## 6  Yes    npreg     5
    
    > ggplot(pima.melt, aes(type, value)) + 
    +     geom_boxplot(outlier.colour = "red") + 
    +     facet_wrap(~variable, 
    +     ncol = 2)
    
    箱线图进行探索性分析

    很难从这张图发现任何明显区别,除了血糖浓度( glu ),也间接说明血糖浓度与糖尿病关系很大。
    这里最大的问题是,不同统计图的单位不同,但却共用一个 Y 轴。所以需要对数据进行标准化处理并重新做图,进行 KNN 时,使所有特征具有同样的测量标准是很重要的。如果不进行标准化,那么对最近邻的距离计算就会出现错误。如果一个特征的测量标准是 1~100 ,那么和另一个测量标准为 1~10 的特征相比,肯定会对结果有更大的影响。

    > pima.scale <- scale(pima[, 1:7]) %>% as_tibble() %>% bind_cols(type = pima$type)
    > head(pima.scale)
    
    ## # A tibble: 6 x 8
    ##    npreg    glu     bp   skin    bmi    ped    age type 
    ##    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <fct>
    ## 1  0.448 -1.13  -0.285 -0.112 -0.391 -0.403 -0.708 No   
    ## 2  1.05   2.39  -0.122  0.363 -1.13  -0.987  2.17  Yes  
    ## 3  0.448 -1.42   0.852  1.12   0.423 -1.01   0.315 No   
    ## 4 -1.06   1.42   0.365  1.31   2.18  -0.708 -0.522 No   
    ## 5 -1.06  -0.453 -0.935 -0.397 -0.943 -1.07  -0.801 No   
    ## 6  0.448 -0.775  0.365 -0.207  0.394 -0.363  1.89  Yes
    
    > # 重新生成箱线图
    > pima.scale %>% melt(id.var = "type") %>% 
    +     ggplot(aes(type, value)) + 
    +     geom_boxplot(outlier.colour = "red") + 
    +     facet_wrap(~variable, ncol = 2)
    
    数据标准化后的箱线图

    标准化之后,除了血糖浓度(glu),年龄(age)也可以看出明显的变化。
    查看各个变量之间的相关性:

    > pima.scale[, 1:7] %>% cor(.) %>% corrplot::corrplot.mixed(.)
    
    变量之间的相关性

    有两对变量之间具有相关性: npreg / age 和 skin / bmi 。
    拆分训练集和测试集,确保数据划分平衡是非常重要的,如果某个结果过于稀疏,就会导致问题,可能引起分类器在优势类和劣势类之间发生偏离。

    > table(pima.scale$type)
    
    ## 
    ##  No Yes 
    ## 355 177
    

    经验法则是,结果中的比例至少应该达到 2 ∶ 1 ,可见刚好满足要求。
    将数据拆分为训练集和测试集:

    > set.seed(120)
    > ind <- sample(2, nrow(pima.scale), replace = T, prob = c(0.7, 0.3))
    > train <- pima.scale[ind == 1, ] %>% as.data.frame()
    > test <- pima.scale[ind == 2, ] %>% as.data.frame()
    > dim(train)
    
    ## [1] 370   8
    
    > dim(test)
    
    ## [1] 162   8
    

    2.2 KNN建模与模型评价

    > grid1 <- expand.grid(.k = seq(2, 20, by = 1))
    > control <- trainControl(method = "cv")
    > set.seed(120)
    > 
    > # 建立计算最优K值的对象
    > knn.train <- train(type ~ ., data = train, method = "knn", trControl = control, tuneGrid = grid1)
    > knn.train
    
    ## k-Nearest Neighbors 
    ## 
    ## 370 samples
    ##   7 predictor
    ##   2 classes: 'No', 'Yes' 
    ## 
    ## No pre-processing
    ## Resampling: Cross-Validated (10 fold) 
    ## Summary of sample sizes: 332, 333, 333, 333, 333, 333, ... 
    ## Resampling results across tuning parameters:
    ## 
    ##   k   Accuracy   Kappa    
    ##   2  0.7270547  0.3567295
    ##   3  0.7785641  0.4636882
    ##   4  0.7999763  0.5132567
    ##   5  0.7945630  0.4991270
    ##   6  0.7756441  0.4625649
    ##   7  0.7918642  0.5000437
    ##   8  0.7673937  0.4522207
    ##   9  0.7892366  0.4958273
    ##   10  0.7893789  0.4891893
    ##   11  0.7756480  0.4626446
    ##   12  0.7945669  0.5058332
    ##   13  0.7918642  0.4906550
    ##   14  0.7920816  0.4910259
    ##   15  0.7891576  0.4795236
    ##   16  0.8055990  0.5188055
    ##   17  0.7892366  0.4821212
    ##   18  0.7784218  0.4540767
    ##   19  0.7784930  0.4501733
    ##   20  0.7731626  0.4332072
    ## 
    ## Accuracy was used to select the optimal model using the largest value.
    ## The final value used for the model was k = 16.
    

    除了得到 k = 16 这个结果之外,我们在输出的表格中还可以看到正确率和 Kappa 统计量的信息,以及交叉验证过程中产生的标准差。正确率告诉我们模型正确分类的百分比。 Kappa 又称科恩的K统计量,通常用于测量两个分类器对观测值分类的一致性。

    查看模型在测试集上的表现:

    > # knn不支持tibble,所以前面转换为dataframe
    > knn.test <- class::knn(train[, -8], test[, -8], train[, 8], k = 16)
    > table(knn.test, test$type)
    
    ##         
    ## knn.test No Yes
    ##      No  90  29
    ##      Yes 13  30
    

    计算准确率:

    > accu <- (90 + 30)/nrow(test)
    > print(accu)
    
    ## [1] 0.7407407
    

    准确率为74%。计算Kappa统计量:

    > prob.chance <- ((90 + 29)/nrow(test)) * ((90 + 13)/nrow(test))
    > print(prob.chance)
    
    ## [1] 0.4670401
    
    > kappa <- (accu - prob.chance)/(1 - prob.chance)
    > print(kappa)
    
    ## [1] 0.5135483
    

    Kappa统计量的值为0.51,根据 Altman 给出的启发式的方法中解释,模型的一致性强度为“中等”。

    2.3 加权最近邻法

    加权最近邻法提高了离观测更近的邻居的影响力,降低了远离观测的邻居的影响力。观测离空间点越远,对它的影响力的惩罚就越大。
    kknn 包中有 10 种不同的加权方式,不加权也是其中之一。它们是: retangular (不加权)、 triangular、 epanechnikov、 biweight、 triweight、 consine、inversion、 gaussian、 rank 和 optimal。

    > set.seed(130)
    > # distance=1 表示绝对值距离, 2 表示欧氏距离)
    > kknn.train <- train.kknn(type ~ ., data = train, kmax = 25, distance = 2, 
    +    kernel = c("rectangular",  "triangular", "epanechnikov"))
    > plot(kknn.train)
    
    加权最近邻

    图中 X 轴表示的是 k 值, Y 轴表示的是核函数误分类观测百分比。可以调用对象看看分类误差和最优参数:

    > kknn.train
    
    ## 
    ## Call:
    ## train.kknn(formula = type ~ ., data = train, kmax = 25, distance = 2, 
    ## + kernel = c("rectangular", "triangular", "epanechnikov"))
    ## 
    ## Type of response variable: nominal
    ## Minimal misclassification: 0.2054054
    ## Best kernel: rectangular
    ## Best k: 11
    

    从上面的数据可以看出,最好的核函数是rectangular,说明给距离加权不能提高模型在训练集上的正确率。看看在测试集上的表现:

    > kknn.pred <- predict(kknn.train, newdata = test)
    > table(kknn.pred, test$type)
    
    ##          
    ## kknn.pred No Yes
    ##       No  90  31
    ##       Yes 13  28
    
    > accu2 <- (90 + 28)/nrow(test)
    > tibble(accu1 = accu, accu2 = accu2) %>% print(.)
    
    ## # A tibble: 1 x 2
    ##   accu1 accu2
    ##   <dbl> <dbl>
    ## 1 0.741 0.728
    

    从结果可以看出,加权最近邻法也不能提高测试集上的正确率。

    2.4 SVM建模与模型评价

    > p_load(e1071, kernlab)
    > 
    > # tune.svm可以帮助我们选择调优参数及核函数,使用交叉验证使调优参数达到最优
    > linear.tune <- tune.svm(type ~ ., data = train, kernel = "linear", 
    +     cost = c(0.001, 0.01, 0.1, 1, 5, 10))
    > summary(linear.tune)
    
    ## 
    ## Parameter tuning of 'svm':
    ## 
    ## - sampling method: 10-fold cross validation 
    ## 
    ## - best parameters:
    ##  cost
    ##     5
    ## 
    ## - best performance: 0.2027027 
    ## 
    ## - Detailed performance results:
    ##    cost     error dispersion
    ## 1 1e-03 0.3189189 0.06955048
    ## 2 1e-02 0.2108108 0.06471454
    ## 3 1e-01 0.2108108 0.04376561
    ## 4 1e+00 0.2054054 0.04628913
    ## 5 5e+00 0.2027027 0.04459232
    ## 6 1e+01 0.2027027 0.04459232
    

    对于这些数据,最优成本函数cost是5,这时的误分类误差率差不多为20%。在测试集上进行预测和检验:

    > best.linear <- linear.tune$best.model
    > tune.test <- predict(best.linear, newdata = test)
    > table(tune.test, test$type)
    
    ##          
    ## tune.test No Yes
    ##       No  93  29
    ##       Yes 10  30
    

    计算准确率:

    > accu.svm <- (93 + 30)/nrow(test)
    > print(accu.svm)
    
    ## [1] 0.7592593
    

    表现比 KNN 稍好一些。现在看看非线性模型能否表现得更好,依然使用交叉验证选择调优参数:

    > set.seed(150)
    > poly.tune <- tune.svm(type ~ ., data = train, kernel = "polynomial", 
    +     degree = c(3, 4, 5), coef0 = c(0.1, 0.5, 1, 2, 3, 4))
    > summary(poly.tune)
    
    ## 
    ## Parameter tuning of 'svm':
    ## 
    ## - sampling method: 10-fold cross validation 
    ## 
    ## - best parameters:
    ##  degree coef0
    ##       3   0.5
    ## 
    ## - best performance: 0.2162162 
    ## 
    ## - Detailed performance results:
    ##    degree coef0     error dispersion
    ## 1       3   0.1 0.2189189 0.06795684
    ## 2       4   0.1 0.2324324 0.05582679
    ## 3       5   0.1 0.2297297 0.05873155
    ## 4       3   0.5 0.2162162 0.05697798
    ## 5       4   0.5 0.2270270 0.05435352
    ## 6       5   0.5 0.2243243 0.05704915
    ## 7       3   1.0 0.2216216 0.04732946
    ## 8       4   1.0 0.2513514 0.05104222
    ## 9       5   1.0 0.2594595 0.05582679
    ## 10      3   2.0 0.2270270 0.05726216
    ## 11      4   2.0 0.2756757 0.05222118
    ## 12      5   2.0 0.2837838 0.05733298
    ## 13      3   3.0 0.2243243 0.05845452
    ## 14      4   3.0 0.2729730 0.06552467
    ## 15      5   3.0 0.2918919 0.08138083
    ## 16      3   4.0 0.2270270 0.05726216
    ## 17      4   4.0 0.2729730 0.06795684
    ## 18      5   4.0 0.2783784 0.08261806
    

    模型选择的多项式阶数为3,核系数为0.5。用这些参数在测试集上进行预测:

    > best.poly <- poly.tune$best.model
    > poly.test <- predict(best.poly, newdata = test)
    > table(poly.test, test$type)
    
    ##          
    ## poly.test No Yes
    ##       No  89  33
    ##       Yes 14  26
    
    > accu.svm.2 <- (89 + 26)/nrow(test)
    > tibble(accu.svm.1 = accu.svm, accu.svm.2 = accu.svm.2) %>% print
    
    ## # A tibble: 1 x 2
    ##   accu.svm.1 accu.svm.2
    ##        <dbl>      <dbl>
    ## 1      0.759      0.710
    

    这个模型的表现还不如线性模型。下面测试径向基核函数,此处只需找出一个参数 gamma,在0.1 ~ 4中依次检验。如果gamma过小,模型就不能解释决策边界的复杂性;如果gamma过大,模型就会严重过拟合。

    > set.seed(150)
    > rbf.tune <- tune.svm(type ~ ., data = train, kernel = "radial", 
    +     gamma = c(0.1, 0.5, 1, 2, 3, 4))
    > summary(rbf.tune)
    
    ## 
    ## Parameter tuning of 'svm':
    ## 
    ## - sampling method: 10-fold cross validation 
    ## 
    ## - best parameters:
    ##  gamma
    ##    0.1
    ## 
    ## - best performance: 0.2054054 
    ## 
    ## - Detailed performance results:
    ##   gamma     error dispersion
    ## 1   0.1 0.2054054 0.06136716
    ## 2   0.5 0.2297297 0.06890567
    ## 3   1.0 0.2702703 0.07429019
    ## 4   2.0 0.3297297 0.08037733
    ## 5   3.0 0.3216216 0.08683301
    ## 6   4.0 0.3189189 0.08622332
    

    最优的 gamma 值是0.1,在测试集上测试:

    > best.rbf <- rbf.tune$best.model
    > rbf.test <- predict(best.rbf, newdata = test)
    > table(rbf.test, test$type)
    
    ##         
    ## rbf.test No Yes
    ##      No  88  32
    ##      Yes 15  27
    

    计算准确率:

    > accu.rbf <- (88 + 27)/nrow(test)
    > print(accu.rbf)
    
    ## [1] 0.7098765
    

    表现可谓惨不忍睹。最后只能看看kernel="sigmoid"了:

    > set.seed(150)
    > sigmoid.tune <- tune.svm(type ~ ., data = train, kernel = "sigmoid", 
    +     gamma = c(0.1, 0.5, 1, 2, 3, 4), coef0 = c(0.1, 0.5, 1, 2, 3, 4))
    > summary(sigmoid.tune)
    
    ## 
    ## Parameter tuning of 'svm':
    ## 
    ## - sampling method: 10-fold cross validation 
    ## 
    ## - best parameters:
    ##  gamma coef0
    ##    0.1   0.1
    ## 
    ## - best performance: 0.2081081 
    ## 
    ## - Detailed performance results:
    ##    gamma coef0     error dispersion
    ## 1    0.1   0.1 0.2081081 0.06747742
    ## 2    0.5   0.1 0.2810811 0.06136716
    ## 3    1.0   0.1 0.3108108 0.08475175
    ## 4    2.0   0.1 0.3081081 0.08753123
    ## 5    3.0   0.1 0.3378378 0.07775980
    ## 6    4.0   0.1 0.2702703 0.07207207
    ## 7    0.1   0.5 0.2621622 0.04942655
    ## 8    0.5   0.5 0.3081081 0.07001571
    ## 9    1.0   0.5 0.3270270 0.08494306
    ## 10   2.0   0.5 0.3000000 0.06036708
    ## 11   3.0   0.5 0.3108108 0.07982002
    ## 12   4.0   0.5 0.2972973 0.09275342
    ## 13   0.1   1.0 0.2702703 0.04225600
    ## 14   0.5   1.0 0.3162162 0.05104222
    ## 15   1.0   1.0 0.3243243 0.08641138
    ## 16   2.0   1.0 0.2945946 0.06036708
    ## 17   3.0   1.0 0.3216216 0.09227090
    ## 18   4.0   1.0 0.3270270 0.09740568
    ## 19   0.1   2.0 0.2270270 0.03648371
    ## 20   0.5   2.0 0.3459459 0.04558238
    ## 21   1.0   2.0 0.3270270 0.04843128
    ## 22   2.0   2.0 0.3405405 0.08936646
    ## 23   3.0   2.0 0.3270270 0.07368687
    ## 24   4.0   2.0 0.3216216 0.07478020
    ## 25   0.1   3.0 0.3189189 0.08622332
    ## 26   0.5   3.0 0.3540541 0.02974338
    ## 27   1.0   3.0 0.3594595 0.05560829
    ## 28   2.0   3.0 0.3000000 0.03916588
    ## 29   3.0   3.0 0.3351351 0.09379759
    ## 30   4.0   3.0 0.3054054 0.07961640
    ## 31   0.1   4.0 0.3189189 0.08622332
    ## 32   0.5   4.0 0.3459459 0.04732946
    ## 33   1.0   4.0 0.3567568 0.04732946
    ## 34   2.0   4.0 0.3243243 0.05697798
    ## 35   3.0   4.0 0.3108108 0.06890567
    ## 36   4.0   4.0 0.3324324 0.06626370
    

    看看在测试集上的表现:

    > best.sigmoid <- sigmoid.tune$best.model
    > sigmoid.test <- predict(best.sigmoid, newdata = test)
    > table(sigmoid.test, test$type)
    
    ##             
    ## sigmoid.test No Yes
    ##          No  90  28
    ##          Yes 13  31
    

    计算准确率:

    > accu.sigmoid <- (90 + 31)/nrow(test)
    > print(accu.sigmoid)
    
    ## [1] 0.7469136
    

    3、模型选择

    > caret::confusionMatrix(sigmoid.test, test$type, positive = "Yes")
    
    ## Confusion Matrix and Statistics
    ## 
    ##           Reference
    ## Prediction No Yes
    ##        No  90  28
    ##        Yes 13  31
    ##                                           
    ##                Accuracy : 0.7469          
    ##                  95% CI : (0.6727, 0.8119)
    ##     No Information Rate : 0.6358          
    ##     P-Value [Acc > NIR] : 0.001717        
    ##                                           
    ##                   Kappa : 0.4221          
    ##                                           
    ##  Mcnemar's Test P-Value : 0.028784        
    ##                                           
    ##             Sensitivity : 0.5254          
    ##             Specificity : 0.8738          
    ##          Pos Pred Value : 0.7045          
    ##          Neg Pred Value : 0.7627          
    ##              Prevalence : 0.3642          
    ##          Detection Rate : 0.1914          
    ##    Detection Prevalence : 0.2716          
    ##       Balanced Accuracy : 0.6996          
    ##                                           
    ##        'Positive' Class : Yes             
    ## 
    

    生成的统计量介绍如下:
     No Information Rate :最大分类所占的比例—— 63% 的人没有糖尿病
     P-Value :用来进行假设检验,说明正确率确实高于No Information Rate
     Mcnemar's Test :我们现在不关心这个统计量,它用于配对分析,主要用于流行病学的研究
     Sensitivity :敏感度,真阳性率;在本案例中,表示没有糖尿病并且被正确识别的比例
     Specificity :特异度,真阴性率;在本案例中,表示有糖尿病并且被正确识别的比例
     Pos Pred Value :阳性预测率,被认为有糖尿病的人中真的有糖尿病的概率
     Neg Pred Value :阴性预测率,被认为没有糖尿病的人中真的没有糖尿病的概率
     Prevalence :患病率,某种疾病在人群中流行度的估计值,本例中的计算方法是第二列(Yes列)中的数之和除以总观测数(矩阵中所有数之和)
     Detection Rate :真阳性预测中被正确识别的比例,在本案例中,用31除以总观测数。
     Detection Prevalence :预测的患病率,在本案例中,底行中的数的和除以总观测数
     Balanced Accuracy :所有类别正确率的平均数。用来表示由于分类器算法中潜在的偏差造成的对最频繁类的过度预测。可以简单地用 (敏感度 + 特异度)/2来计算

    使用这些结果与线性SVM模型对比:

    > confusionMatrix(tune.test, test$type, positive = "Yes")
    
    ## Confusion Matrix and Statistics
    ## 
    ##           Reference
    ## Prediction No Yes
    ##        No  93  29
    ##        Yes 10  30
    ##                                           
    ##                Accuracy : 0.7593          
    ##                  95% CI : (0.6859, 0.8229)
    ##     No Information Rate : 0.6358          
    ##     P-Value [Acc > NIR] : 0.0005302       
    ##                                           
    ##                   Kappa : 0.4418          
    ##                                           
    ##  Mcnemar's Test P-Value : 0.0039478       
    ##                                           
    ##             Sensitivity : 0.5085          
    ##             Specificity : 0.9029          
    ##          Pos Pred Value : 0.7500          
    ##          Neg Pred Value : 0.7623          
    ##              Prevalence : 0.3642          
    ##          Detection Rate : 0.1852          
    ##    Detection Prevalence : 0.2469          
    ##       Balanced Accuracy : 0.7057          
    ##                                           
    ##        'Positive' Class : Yes             
    ## 
    

    两个模型的结果差不多,线性SVM模型的准确率稍微还要高一些。

    4、SVM中的特征选择

    前面做的工作就是把特征堆在一起,作为所谓的输入空间,然后让 SVM 这个黑盒去计算,最后给出一个预测分类。使用 SVM 的一个主要问题就是,它给出的结果非常难以解释。
    但是,还有一些其他办法可以进行特征选择:

    > set.seed(150)
    > rfeCNTL <- rfeControl(functions = lrFuncs, method = "cv", number = 10)
    > 
    > # rfe() 函数执行一个递归的特征选择过程 
    > # functions可以使用几种不同的参数,此处使用lrFuncs
    > # sizes 指定输入特征的数量 kernlab包中的线性方法svmLinear,还有其他选项
    > svm.features <- rfe(train[, 1:7], train[, 8], sizes = c(7, 6, 5, 4), 
    +     rfeControl = rfeCNTL, method = "svmLinear")
    > # 查看不同数量特征模型的表现
    > svm.features
    
    ## 
    ## Recursive feature selection
    ## 
    ## Outer resampling method: Cross-Validated (10 fold) 
    ## 
    ## Resampling performance over subset size:
    ## 
    ##  Variables Accuracy  Kappa AccuracySD KappaSD Selected
    ##          4   0.7972 0.5055    0.05044  0.1189         
    ##          5   0.7973 0.5094    0.04839  0.1175        *
    ##          6   0.7945 0.5025    0.05096  0.1190         
    ##          7   0.7945 0.5025    0.05096  0.1190         
    ## 
    ## The top 5 variables (out of 5):
    ##    glu, npreg, bmi, ped, bp
    

    出乎意料,五特征模型表现得相当好。看看在测试集上的表现:

    > svm.5 <- svm(type ~ glu + npreg + bmi + ped + bp, data = train, kernel = "linear")
    > test.new <- test %>% select(c("glu", "npreg", "bmi", "ped", "bp"))
    > svm.5.predict <- predict(svm.5, newdata = test.new)
    > confusionMatrix(svm.5.predict, test$type, positive = "Yes")
    
    ## Confusion Matrix and Statistics
    ## 
    ##           Reference
    ## Prediction No Yes
    ##        No  91  29
    ##        Yes 12  30
    ##                                           
    ##                Accuracy : 0.7469          
    ##                  95% CI : (0.6727, 0.8119)
    ##     No Information Rate : 0.6358          
    ##     P-Value [Acc > NIR] : 0.001717        
    ##                                           
    ##                   Kappa : 0.4177          
    ##                                           
    ##  Mcnemar's Test P-Value : 0.012462        
    ##                                           
    ##             Sensitivity : 0.5085          
    ##             Specificity : 0.8835          
    ##          Pos Pred Value : 0.7143          
    ##          Neg Pred Value : 0.7583          
    ##              Prevalence : 0.3642          
    ##          Detection Rate : 0.1852          
    ##    Detection Prevalence : 0.2593          
    ##       Balanced Accuracy : 0.6960          
    ##                                           
    ##        'Positive' Class : Yes             
    ## 
    

    表现与全特征模型差不多。通过反复实验,你可以看到这种方法是如何工作的,它的目的是对特征重要性做一个简单的鉴别。

    总结:

    • 1.KNN,包括不加权和加权的最近邻算法;
    • 2.SVM,包括线性和非线性支持向量机;
    • 3.使用caret包进行粗略的特征选择。

    相关文章

      网友评论

        本文标题:43-R语言机器学习:K最近邻与支持向量机

        本文链接:https://www.haomeiwen.com/subject/cpvjdhtx.html