该篇文章主要针对葡萄酒数据,分别采用KNN和朴素贝叶斯算法实现葡萄酒品种的多分类预测,其中涉及数据集的描述性统计、标准化处理、训练集测试集的随机划分,模型效果评估,特征主成分提取,预测效果可视化等内容。
1问题背景
对于葡萄酒数据(wine.csv),请分别使用kNN和朴素贝叶斯方法构建分类器来预测第1列中给出的品种。在50%数据的随机子集上训练分类器。然后预测其余50%数据的品种,并将其绘制在二维空间中(使用不同的pch),同时评估分类器效果。
2 整体步骤
1.加载实验所需的相关包,并读取数据文件;2.对原始数据的数据类型,数据指标情况进行探索;3.创建标准化函数,对解释变量进行标准化,并通过设置随机种子的方式,将数据集随机划分为训练集、测试集分别约占50%的两个数据集;4.分别通过训练集数据训练KNN和朴素贝叶斯模型,然后将测试集预测的葡萄酒种类绘制到前两个主成分的二维空间中(使用不同的pch);5.使用准确率和混淆矩阵的结果评估分类器效果,其中KNN模型在测试集中预测准确率达到93.18%,朴素贝叶斯模型在测试集中预测准确率达到95.45%。总体上看,在葡萄酒品种预测中,朴素贝叶斯模型的表现更好。
3 操作实战
3.1 第一步——加载包并读取数据
运行程序:
1. #加载包 2. library("class") 3. library("caret") 4. library("gmodels") 5. #读取数据 6. data<- read.csv("D:\\研\\机器学习与R语言\\wine.csv",header = T)
3.2 第二步——探索和准备数据
1)使用str()发现,该数据集共有178个观测值,14个特征(变量),同时,其涉及的数据类型有整型(int)和数值型(num),其中“cultivars”为目标变量。
> str(data) #查看数据类型 'data.frame': 178 obs. of 14 variables: $ cultivars : int 1 1 1 1 1 1 1 1 1 1 ... $ Alcohol : num 14.2 13.2 13.2 14.4 13.2 ... $ Malic.acid : num 1.71 1.78 2.36 1.95 2.59 1.76 1.87 2.15 1.64 1.35 ... $ Ash : num 2.43 2.14 2.67 2.5 2.87 2.45 2.45 2.61 2.17 2.27 ... $ Alcalinity.of.ash. : num 15.6 11.2 18.6 16.8 21 15.2 14.6 17.6 14 16 ... $ Magnesium : int 127 100 101 113 118 112 96 121 97 98 ... $ Total.phenols : num 2.8 2.65 2.8 3.85 2.8 3.27 2.5 2.6 2.8 2.98 ... $ Flavanoids : num 3.06 2.76 3.24 3.49 2.69 3.39 2.52 2.51 2.98 3.15 ... $ Nonflavanoid.phenols : num 0.28 0.26 0.3 0.24 0.39 0.34 0.3 0.31 0.29 0.22 ... $ Proanthocyanins : num 2.29 1.28 2.81 2.18 1.82 1.97 1.98 1.25 1.98 1.85 ... $ Color.intensity : num 5.64 4.38 5.68 7.8 4.32 6.75 5.25 5.05 5.2 7.22 ... $ Hue : num 1.04 1.05 1.03 0.86 1.04 1.05 1.02 1.06 1.08 1.01 ... $ OD280.OD315.of.diluted.wines: num 3.92 3.4 3.17 3.45 2.93 2.85 3.58 3.58 2.85 3.55 ... $ Proline : int 1065 1050 1185 1480 735 1450 1290 1295 1045 1045 ...
2)使用table()函数输出数据集葡萄酒品种情况,发现,该数据集中,葡萄酒品种共有三种,数据量分别为59,71,48。
> table(data$cultivars) 1 2 3 59 71 48
3)使用factor()将目标属性(葡萄酒品种)编码为因子类型。
> data$cultivars<-factor(data$cultivars,levels=c('1','2','3'), + labels=c('第一类','第二类','第三类')) > > str(data$cultivars) Factor w/ 3 levels "第一类","第二类",..: 1 1 1 1 1 1 1 1 1 1 ...
4)查看不同葡萄酒品种占数据集比例,三种品种比例分别为33.1%,39.9%,27.0%。
> round(prop.table(table(data$cultivars))*100,digits = 1) 第一类 第二类 第三类 33.1 39.9 27.0
5)利用summary()查看各特征数据情况,见下图,包括每个特征的最小值,1/4分位数,中位数,均值,3/4分位数,最大值。由于KNN的距离计算很大程度上依赖输入特征的测量尺度,特征“Proline”的值范围为278~1680。可能导致后续分类存在问题,所以,应用min-max将这些特征进行标准化,将其调整到一个标准范围内。
> summary(data[c('Alcohol','Malic.acid','Ash','Alcalinity.of.ash.', + 'Magnesium','Total.phenols','Flavanoids','Nonflavanoid.phenols', + 'Proanthocyanins','Color.intensity','Hue','OD280.OD315.of.diluted.wines', + 'Proline')]) Alcohol Malic.acid Ash Alcalinity.of.ash. Min. :11.03 Min. :0.740 Min. :1.360 Min. :10.60 1st Qu.:12.36 1st Qu.:1.603 1st Qu.:2.210 1st Qu.:17.20 Median :13.05 Median :1.865 Median :2.360 Median :19.50 Mean :13.00 Mean :2.336 Mean :2.367 Mean :19.49 3rd Qu.:13.68 3rd Qu.:3.083 3rd Qu.:2.558 3rd Qu.:21.50 Max. :14.83 Max. :5.800 Max. :3.230 Max. :30.00 Magnesium Total.phenols Flavanoids Nonflavanoid.phenols Min. : 70.00 Min. :0.980 Min. :0.340 Min. :0.1300 1st Qu.: 88.00 1st Qu.:1.742 1st Qu.:1.205 1st Qu.:0.2700 Median : 98.00 Median :2.355 Median :2.135 Median :0.3400 Mean : 99.74 Mean :2.295 Mean :2.029 Mean :0.3619 3rd Qu.:107.00 3rd Qu.:2.800 3rd Qu.:2.875 3rd Qu.:0.4375 Max. :162.00 Max. :3.880 Max. :5.080 Max. :0.6600 Proanthocyanins Color.intensity Hue Min. :0.410 Min. : 1.280 Min. :0.4800 1st Qu.:1.250 1st Qu.: 3.220 1st Qu.:0.7825 Median :1.555 Median : 4.690 Median :0.9650 Mean :1.591 Mean : 5.058 Mean :0.9574 3rd Qu.:1.950 3rd Qu.: 6.200 3rd Qu.:1.1200 Max. :3.580 Max. :13.000 Max. :1.7100 OD280.OD315.of.diluted.wines Proline Min. :1.270 Min. : 278.0 1st Qu.:1.938 1st Qu.: 500.5 Median :2.780 Median : 673.5 Mean :2.612 Mean : 746.9 3rd Qu.:3.170 3rd Qu.: 985.0 Max. :4.000 Max. :1680.0
6)创建normalize函数,并利用lapply()将葡萄酒的各特征进行标准化处理,代码如下:
1. normalize<-function(x){ 2. return ((x-min(x))/(max(x)-min(x))) 3. } 4. features<-as.data.frame(lapply(data[2:14],normalize))
7)随机化创建训练集和测试集。通过seed()设置随机种子,利sample()随机的从1~178的整数序列中选一般的值构成一个整数向量,通过使用该向量将数据集分割为50%的训练集和50%的测试数据集。同时,查看训练集和测试集数据的分割情况,发现两个数据集各葡萄酒类别占比相似,可以建立模型进行训练预测。
运行程序:
1. # 将数据集划分为训练集和测试集 2. set.seed(123) # 设置随机种子以确保结果的可重复性 3. trainIndex <- sample(178,178/2) 4. data_train<-features[trainingIndex,] #创建训练集 5. data_test<-features[-trainingIndex,] #创建测试集 6. data_train_lables<-data[trainingIndex,1] #存储因子向量型训练集类签 7. data_test_lables<-data[-trainingIndex,1] #存储因子向量型测试集类标签
运行结果:
> round(prop.table(table(data_train_lables))*100,digits = 1) data_train_lables 第一类 第二类 第三类 33.3 40.0 26.7 > round(prop.table(table(data_test_lables))*100,digits = 1) data_test_lables 第一类 第二类 第三类 33.0 39.8 27.3
3.3 第三步——基于数据训练模型KNN模型并进行模型效果评估
1)使用knn()函数对测试数据进行分类,初始值k设置为3,函数knn()返回一个因子向量,为测试集中每一个案例返回一个预测标签,将其命名为data_test_pred。
运行程序:
1. ##KNN分类器 2. # 使用kNN构建分类器 3. data_test_pred<-knn(train = data_train,test = data_test,cl<-data_train_lables,k=3)
2)首先利用prcomp()提取所有解释变量的前两个主成分,将其分别作为葡萄酒预测类型的X轴和Y轴进行可视化。从下图可以看出三种类别的葡萄酒数据位置存在明显的聚集现象,说明同一类别数据具有较高相似性。
运行程序:
1. ##预测结果绘图:KNN模型 2. # 选择前两个主成分进行绘图 3. pca_results <- prcomp(data_test, scale = F) 4. plot_features <- pca_results$x[, 1:2] 5. plot_data <- data.frame(plot_features, Actual =data_test_lables, Predicted_kNN =data_test_pred, Predicted_GNB=nb_pred) 6. ggplot(plot_data, aes(x = plot_data[, 1], y = plot_data[, 2], color = Predicted_kNN, shape = Predicted_kNN)) + 7. geom_point(size = 3, alpha = 0.6) + 8. scale_color_manual(values = c("red", "blue", "green")) + # 假设有三个品种,使用不同颜色 9. scale_shape_manual(values = c(1, 2, 3)) + # 使用默认的三种形状,并设置图例标题 10. labs(title = "kNN Predictions on Test Set", x = "Feature 1", y = "Feature 2") + # 删除color参数,因为我们在scale_shape_manual中设置了name 11. theme_minimal()
运行结果:
3)使用正确率和混淆矩阵评估模型优劣。根据计算KNN模型预测结果发现,在测试集中,模型预测准确率达到93.18%。具体结果如下:
> cat("kNN Accuracy:", knn_accuracy, "\n") kNN Accuracy: 0.9318182 > #混淆矩阵 > CrossTable(x=data_test_lables,y=data_test_pred,prop.chisq = F) Cell Contents |-------------------------| | N | | N / Row Total | | N / Col Total | | N / Table Total | |-------------------------| Total Observations in Table: 88 | data_test_pred data_test_lables | 第一类 | 第二类 | 第三类 | Row Total | --------------|-----------|-----------|-----------|-----------| 第一类 | 29 | 0 | 0 | 29 | | 1.000 | 0.000 | 0.000 | 0.330 | | 0.967 | 0.000 | 0.000 | | | 0.330 | 0.000 | 0.000 | | -----------------|-----------|-----------|-----------|-----------| 第二类 | 1 | 30 | 4 | 35 | | 0.029 | 0.857 | 0.114 | 0.398 | | 0.033 | 0.968 | 0.148 | | | 0.011 | 0.341 | 0.045 | | -----------------|-----------|-----------|-----------|-----------| 第三类 | 0 | 1 | 23 | 24 | | 0.000 | 0.042 | 0.958 | 0.273 | | 0.000 | 0.032 | 0.852 | | | 0.000 | 0.011 | 0.261 | | -----------------|-----------|-----------|-----------|-----------| Column Total | 30 | 31 | 27 | 88 | | 0.341 | 0.352 | 0.307 | | -----------------|-----------|-----------|-----------|-----------|
通过KNN模型预测效果的混淆矩阵,发现,第一类葡萄酒完全预测正确,第二类葡萄酒有一个被预测为第一类,4个被预测为第三类,有一个被预测为第一类,第三类葡萄酒有1个被预测为第二类,总体预测效果良好。
3.4 第四步——基于数据训练模型朴素贝叶斯模型并进行模型效果评估
1)使用naiveBayes()函数训练数据,将模型保存到nb_model,并使用predict将预测结果保存到nb_pred。
运行程序:
1. ##朴素贝叶斯分类器 2. nb_model <- naiveBayes(data_train, data_train_lables) 3. nb_pred <- predict(nb_model, data_test)
2)将朴素贝叶斯预测结果,绘制到二维平面发现,各类别葡萄酒分类效果明显。
运行程序:
1. ggplot(plot_data, aes(x = plot_data[, 1], y = plot_data[, 2], color = Predicted_GNB, shape = Predicted_GNB)) + 2. geom_point(size = 3, alpha = 0.6) + 3. scale_color_manual(values = c("red", "blue", "green")) + # 假设有三个品种,使用不同颜色 4. scale_shape_manual(values = c(1, 2, 3)) + # 使用默认的三种形状,并设置图例标题 5. labs(title = "kNN Predictions on Test Set", x = "Feature 1", y = "Feature 2") + # 删除color参数,因为我们在scale_shape_manual中设置了name 6. theme_minimal()
运行结果:
3)使用正确率和混淆矩阵评估模型优劣。根据计算朴素贝叶斯模型预测结果发现,在测试集中,模型预测准确率达到95.45%。具体结果如下:
> # 评估朴素贝叶斯分类器 > nb_confusion_matrix <- table(data_test_lables, nb_pred) > nb_accuracy <- sum(diag(nb_confusion_matrix)) / sum(nb_confusion_matrix) > cat("Naive Bayes Accuracy:", nb_accuracy, "\n") Naive Bayes Accuracy: 0.9545455 > > ##评估分类器:朴素贝叶斯 > ##混淆矩阵 > CrossTable(x=nb_pred,y=data_test_pred,prop.chisq = F) Cell Contents |-------------------------| | N | | N / Row Total | | N / Col Total | | N / Table Total | |-------------------------| Total Observations in Table: 88 | data_test_pred nb_pred | 第一类 | 第二类 | 第三类 | Row Total | -------------|-----------|-----------|-----------|-----------| 第一类 | 30 | 1 | 0 | 31 | | 0.968 | 0.032 | 0.000 | 0.352 | | 1.000 | 0.032 | 0.000 | | | 0.341 | 0.011 | 0.000 | | -------------|-----------|-----------|-----------|-----------| 第二类 | 0 | 28 | 3 | 31 | | 0.000 | 0.903 | 0.097 | 0.352 | | 0.000 | 0.903 | 0.111 | | | 0.000 | 0.318 | 0.034 | | -------------|-----------|-----------|-----------|-----------| 第三类 | 0 | 2 | 24 | 26 | | 0.000 | 0.077 | 0.923 | 0.295 | | 0.000 | 0.065 | 0.889 | | | 0.000 | 0.023 | 0.273 | | -------------|-----------|-----------|-----------|-----------| Column Total | 30 | 31 | 27 | 88 | | 0.341 | 0.352 | 0.307 | | -------------|-----------|-----------|-----------|-----------|
通过朴素贝叶斯模型预测效果的混淆矩阵,发现,第一类葡萄酒有一个被预测为第二类,第二类葡萄酒有3个被预测为第三类,第三类葡萄酒有两个被预测为第2类,总体预测效果良好。
4 完整代码
1. #加载包 2. library("class") 3. library("caret") 4. library("gmodels") 5. #读取数据 6. data<- read.csv("D:\\研\\机器学习与R语言\\wine.csv",header = T) 7. str(data) #查看数据类型 8. 9. table(data$cultivars) #查看葡萄酒品种情况 10. 11. data$cultivars<-factor(data$cultivars,levels=c('1','2','3'), 12. labels=c('第一类','第二类','第三类')) 13. 14. str(data$cultivars) 15. 16. round(prop.table(table(data$cultivars))*100,digits = 1) 17. colnames(data) 18. summary(data[c('Alcohol','Malic.acid','Ash','Alcalinity.of.ash.', 19. 'Magnesium','Total.phenols','Flavanoids','Nonflavanoid.phenols', 20. 'Proanthocyanins','Color.intensity','Hue','OD280.OD315.of.diluted.wines', 21. 'Proline')]) 22. 23. normalize<-function(x){ 24. return ((x-min(x))/(max(x)-min(x))) 25. } 26. features<-as.data.frame(lapply(data[2:14],normalize)) 27. 28. 29. 30. # 将数据集划分为训练集和测试集 31. set.seed(123) # 设置随机种子以确保结果的可重复性 32. trainIndex <- sample(178,178/2) 33. data_train<-features[trainingIndex,] #创建训练集 34. data_test<-features[-trainingIndex,] #创建测试集 35. data_train_lables<-data[trainingIndex,1] #存储因子向量型训练集类标签 36. data_test_lables<-data[-trainingIndex,1] #存储因子向量型测试集类标签 37. 38. ##查看分割情况 39. round(prop.table(table(data_train_lables))*100,digits = 1) 40. round(prop.table(table(data_test_lables))*100,digits = 1) 41. 42. 43. ##KNN分类器 44. # 使用kNN构建分类器 45. data_test_pred<-knn(train = data_train,test = data_test,cl<-data_train_lables,k=3) 46. 47. ##朴素贝叶斯分类器 48. nb_model <- naiveBayes(data_train, data_train_lables) 49. nb_pred <- predict(nb_model, data_test) 50. 51. ##预测结果绘图:KNN模型 52. # 选择前两个主成分进行绘图 53. pca_results <- prcomp(data_test, scale = F) 54. plot_features <- pca_results$x[, 1:2] 55. plot_data <- data.frame(plot_features, Actual =data_test_lables, Predicted_kNN =data_test_pred, Predicted_GNB=nb_pred) 56. ggplot(plot_data, aes(x = plot_data[, 1], y = plot_data[, 2], color = Predicted_kNN, shape = Predicted_kNN)) + 57. geom_point(size = 3, alpha = 0.6) + 58. scale_color_manual(values = c("red", "blue", "green")) + # 假设有三个品种,使用不同颜色 59. scale_shape_manual(values = c(1, 2, 3)) + # 使用默认的三种形状,并设置图例标题 60. labs(title = "kNN Predictions on Test Set", x = "Feature 1", y = "Feature 2") + # 删除color参数,因为我们在scale_shape_manual中设置了name 61. theme_minimal() 62. 63. 64. ##评估分类器:KNN 65. # 评估kNN分类器 66. knn_confusion_matrix <- table(data_test_lables, data_test_pred) 67. knn_accuracy <- sum(diag(knn_confusion_matrix)) / sum(knn_confusion_matrix) 68. cat("kNN Accuracy:", knn_accuracy, "\n") 69. #混淆矩阵 70. CrossTable(x=data_test_lables,y=data_test_pred,prop.chisq = F) 71. 72. 73. 74. 75. ggplot(plot_data, aes(x = plot_data[, 1], y = plot_data[, 2], color = Predicted_GNB, shape = Predicted_GNB)) + 76. geom_point(size = 3, alpha = 0.6) + 77. scale_color_manual(values = c("red", "blue", "green")) + # 假设有三个品种,使用不同颜色 78. scale_shape_manual(values = c(1, 2, 3)) + # 使用默认的三种形状,并设置图例标题 79. labs(title = "kNN Predictions on Test Set", x = "Feature 1", y = "Feature 2") + # 删除color参数,因为我们在scale_shape_manual中设置了name 80. theme_minimal()