5分钟用R内置数据构建你的第一个机器学习模型:鸢尾花分类实战

从零开始的机器学习初体验

当你第一次接触机器学习时,最令人望而生畏的往往不是算法本身,而是数据准备的过程。数据清洗、特征工程这些专业术语让许多初学者在还没开始建模前就已经打退堂鼓。但今天我要告诉你一个秘密:R语言内置的datasets包中,藏着完美的"练手"数据集,让你可以跳过繁琐的数据准备,直接进入模型构建的精彩环节。

iris数据集(在R中表现为iris3数组)就是这样一个完美的起点。它包含了三种鸢尾花(Setosa、Versicolor和Virginica)各50个样本的四个特征测量值:萼片长度、萼片宽度、花瓣长度和花瓣宽度。这些数据已经经过整理,不存在缺失值,特征尺度相近,且具有清晰的分类边界,特别适合机器学习入门。

"好的开始是成功的一半。选择iris数据集作为第一个机器学习项目,就像学游泳时先在浅水区练习——安全且有效。" —— 一位数据科学教育者的经验之谈

1. 环境准备与数据探索

1.1 加载必要包与数据

在R中开始机器学习之旅非常简单,我们甚至不需要安装额外的包。基础安装中的datasetsstats就包含了我们需要的一切:

# 加载内置数据集
data(iris3)  # 这是三维数组形式的鸢尾花数据
iris_df <- data.frame(
  Sepal.Length = c(iris3[,1,1], iris3[,1,2], iris3[,1,3]),
  Sepal.Width = c(iris3[,2,1], iris3[,2,2], iris3[,2,3]),
  Petal.Length = c(iris3[,3,1], iris3[,3,2], iris3[,3,3]),
  Petal.Width = c(iris3[,4,1], iris3[,4,2], iris3[,4,3]),
  Species = rep(c("Setosa", "Versicolor", "Virginica"), each = 50)
)

1.2 快速了解数据

在建模前,让我们先花1分钟了解数据的基本情况:

# 查看数据结构
str(iris_df)

# 统计摘要
summary(iris_df)

# 检查类别分布
table(iris_df$Species)

通过这简单的探索,我们已经可以得出几个关键结论:

  • 数据集包含150个观测,无缺失值
  • 三种鸢尾花各50个样本,完全平衡
  • 四个特征都是数值型,尺度相近(厘米为单位)

1.3 可视化数据关系

可视化是理解数据最直观的方式。让我们用散点图矩阵快速查看特征间的关系:

pairs(iris_df[,1:4], col = iris_df$Species, pch = 19,
      main = "鸢尾花特征散点图矩阵")

从图中可以明显看出:

  • Setosa与其他两种在花瓣尺寸上有明显区别
  • Versicolor和Virginica有一定重叠,但仍有可分性
  • 花瓣长度和宽度可能是最重要的分类特征

2. 构建你的第一个分类模型

2.1 数据分割

在机器学习中,我们通常将数据分为训练集和测试集。这里我们采用简单的70-30分割:

set.seed(123)  # 确保结果可重现
train_idx <- sample(1:nrow(iris_df), 0.7 * nrow(iris_df))
train_data <- iris_df[train_idx, ]
test_data <- iris_df[-train_idx, ]

2.2 选择并训练模型

对于分类问题,我们有多种算法可选。作为第一个模型,我们从简单直观的k最近邻(KNN)开始:

# 使用class包中的knn函数
library(class)

# 准备训练和测试数据(去除Species列)
train_features <- train_data[, -5]
test_features <- test_data[, -5]
train_labels <- train_data$Species

# 训练KNN模型(k=3)
knn_model <- knn(train = train_features, 
                 test = test_features,
                 cl = train_labels,
                 k = 3)

2.3 模型评估

现在让我们看看模型的表现如何:

# 混淆矩阵
confusion_matrix <- table(Actual = test_data$Species, Predicted = knn_model)
print(confusion_matrix)

# 计算准确率
accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
cat("模型准确率:", round(accuracy, 3))

典型输出结果可能如下:

Actual\PredictedSetosaVersicolorVirginica
Setosa1500
Versicolor0132
Virginica0114

模型准确率: 0.933

这意味着我们的简单模型在测试集上达到了约93.3%的准确率,对于第一个模型来说已经相当不错!

3. 模型优化与比较

3.1 调整KNN参数

KNN的性能很大程度上取决于k值的选择。让我们尝试不同的k值:

# 尝试不同的k值
k_values <- 1:10
accuracies <- sapply(k_values, function(k) {
  pred <- knn(train_features, test_features, train_labels, k)
  sum(pred == test_data$Species) / nrow(test_data)
})

# 绘制k值与准确率关系图
plot(k_values, accuracies, type = "b", pch = 19, 
     xlab = "k值", ylab = "准确率",
     main = "KNN不同k值的表现")

从图中我们可以选择一个表现最佳的k值(通常在3-5之间)。

3.2 尝试决策树算法

除了KNN,决策树是另一个直观易懂的算法。让我们用rpart包试试:

library(rpart)

# 训练决策树模型
tree_model <- rpart(Species ~ ., data = train_data, method = "class")

# 可视化决策树
library(rpart.plot)
rpart.plot(tree_model, main = "鸢尾花分类决策树")

决策树的一个优势是我们可以直接看到模型是如何做决策的。例如,它可能首先根据花瓣长度将Setosa分离出来,然后再通过花瓣宽度区分Versicolor和Virginica。

3.3 模型比较

让我们比较两种模型在测试集上的表现:

模型类型准确率优点缺点
KNN (k=3)93.3%简单直观,无需训练过程预测速度慢,对k值敏感
决策树95.6%可解释性强,速度快可能过拟合,对数据变化敏感

4. 深入理解模型表现

4.1 分析分类错误

即使模型整体准确率高,了解它在哪里出错也很重要。回到我们的KNN混淆矩阵:

  • Setosa类被完美分类(15/15正确)
  • Versicolor有2个被误判为Virginica
  • Virginica有1个被误判为Versicolor

这告诉我们:

  1. Setosa与其他两类区分度最高
  2. Versicolor和Virginica的边界区域存在混淆

4.2 特征重要性分析

哪些特征对分类贡献最大?我们可以通过多种方式评估:

# 使用决策树的特征重要性
tree_model$variable.importance

# 使用随机森林(如果已安装randomForest包)
# library(randomForest)
# rf_model <- randomForest(Species ~ ., data = train_data)
# importance(rf_model)

典型结果可能显示花瓣尺寸(长度和宽度)比萼片尺寸更重要。

4.3 决策边界可视化

让我们可视化KNN在两个最重要特征上的决策边界:

library(ggplot2)
library(class)

# 只使用花瓣长度和宽度
train_reduced <- train_data[, c("Petal.Length", "Petal.Width", "Species")]
test_reduced <- test_data[, c("Petal.Length", "Petal.Width", "Species")]

# 生成网格点用于绘制决策边界
grid_size <- 0.02
petal_length_range <- seq(min(iris_df$Petal.Length), max(iris_df$Petal.Length), by = grid_size)
petal_width_range <- seq(min(iris_df$Petal.Width), max(iris_df$Petal.Width), by = grid_size)
grid <- expand.grid(Petal.Length = petal_length_range, 
                    Petal.Width = petal_width_range)

# 预测网格点的类别
grid_pred <- knn(train = train_reduced[,1:2], 
                 test = grid,
                 cl = train_reduced$Species,
                 k = 3)

# 绘制决策边界
ggplot() +
  geom_tile(data = cbind(grid, Species = grid_pred), 
            aes(x = Petal.Length, y = Petal.Width, fill = Species),
            alpha = 0.3) +
  geom_point(data = test_reduced, 
             aes(x = Petal.Length, y = Petal.Width, color = Species),
             size = 3) +
  labs(title = "KNN决策边界(基于花瓣尺寸)",
       x = "花瓣长度", y = "花瓣宽度") +
  theme_minimal()

这张图清晰地展示了:

  • Setosa(左下角)有明确的边界
  • Versicolor和Virginica之间的边界较为复杂
  • 分类错误大多发生在两类重叠的区域

5. 项目扩展与下一步

5.1 尝试其他算法

现在你已经成功构建了第一个模型,可以尝试其他算法:

# 逻辑回归(需要将问题转化为二元分类)
# 线性判别分析(LDA)
library(MASS)
lda_model <- lda(Species ~ ., data = train_data)
lda_pred <- predict(lda_model, test_data)$class
table(Actual = test_data$Species, Predicted = lda_pred)

# 支持向量机(SVM)
library(e1071)
svm_model <- svm(Species ~ ., data = train_data, kernel = "linear")
svm_pred <- predict(svm_model, test_data)
table(Actual = test_data$Species, Predicted = svm_pred)

5.2 交叉验证评估

更可靠的模型评估方法是交叉验证:

library(caret)
ctrl <- trainControl(method = "cv", number = 10)
knn_cv <- train(Species ~ ., data = iris_df, method = "knn",
                trControl = ctrl, tuneLength = 10)
print(knn_cv)

5.3 应用到其他内置数据集

掌握了这些技能后,你可以轻松应用到R中其他内置数据集:

# 使用mtcars数据集预测汽车档位
data(mtcars)
mtcars$gear <- as.factor(mtcars$gear)

# 使用USArrests数据集进行聚类分析
data(USArrests)

5.4 真实项目中的注意事项

虽然iris数据集很友好,但真实项目通常更复杂:

  • 数据可能有缺失值和异常值
  • 特征尺度可能差异很大
  • 类别可能不平衡
  • 需要更复杂的特征工程

但通过这个简单项目,你已经掌握了机器学习工作流的核心步骤:数据准备、模型构建、评估和优化。这些技能将为你处理更复杂的问题奠定坚实基础。

更多推荐