You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言随机森林调参报错及自动寻优实现咨询

作物分类模型问题分析与解决

问题背景

拥有如下作物分类数据集:

mydata=structure(list(crop_name = c("Guar", "Guar", "Guar", "Guar", 
    "Guar", "Guar", "Guar", "Guar", "Guar", "Guar", "Bajra", "Bajra", 
    "Bajra", "Bajra", "Bajra", "Bajra", "Bajra", "Bajra", "Bajra", 
    "Bajra"), B08A = c(2781L, 2817L, 2700L, 1780L, 3702L, 4094L, 
    3921L, 3780L, 2855L, 3501L, 2963L, 2578L, 1996L, 4502L, 4217L, 
    3528L, 3689L, 3529L, 3050L, 2996L), nir = c(2576L, 2607L, 2328L, 
    1541L, 3329L, 3681L, 3636L, 3382L, 2481L, 3174L, 2820L, 2691L, 
    2318L, 4229L, 3868L, 3648L, 3271L, 3244L, 2497L, 2752L), swir = c(2866L, 
    3589L, 2782L, 1447L, 2784L, 3084L, 3019L, 2972L, 1779L, 2687L, 
    3889L, 2332L, 1570L, 2574L, 2910L, 2546L, 2953L, 3176L, 3198L, 
    3464L), gcvi = c(0.624211853, 1.065768621, 0.897310513, 0.861111111, 
    1.384670487, 2.349408553, 2.246428571, 1.756316218, 1.753607103, 
    2.933085501, 0.923601637, 0.996290801, 2.274011299, 2.311667971, 
    3.084477296, 2.86031746, 2.494658119, 2.164878048, 1.824660633, 
    1.596226415)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
    -20L))

需求:构建分类器预测作物类别(Bajra和Guar),自动枚举随机森林超参数,使模型F-measure达到至少90%;若无法达到则返回最高精度。

编写的代码如下:

library(caret)
library(randomForest)

# Convert the factor variable to a numeric one
mydata$crop_name <- as.numeric(mydata$crop_name) - 1

# We split the data into training and test samples
set.seed(123)
trainIndex <- createDataPartition(mydata$crop_name, p = 0.8, list = FALSE)
trainData <- mydata[trainIndex, ]
testData <- mydata[-trainIndex, ]

# Define a function to evaluate the model
evaluate_model <- function(model, testData) {
 predictions <- predict(model, testData)
 confusionMatrix <- confusionMatrix(data = factor(predictions, levels = c(0, 1)),
 reference = factor(testData$crop_name, levels = c(0, 1)),
 positive = "1")
 precision <- confusionMatrix$byClass['Pos Pred Value']
 recall <- confusionMatrix$byClass['Sensitivity']
 f1 <- 2 * precision * recall / (precision + recall)
 return(list(precision = precision, recall = recall, f1 = f1))
}

# **Random Forest**

# Define a grid of parameters for searching
rfGrid <- expand.grid(mtry = c(2, 3, 4),
 ntree = c(500, 1000, 1500))

best_rf_f1 <- 0

# Enumerate random forest parameters
for (i in 1:nrow(rfGrid)) {
 # Model training
 rfModel <- randomForest(crop_name ~ ., data = trainData,
 mtry = rfGrid$mtry[i],
 ntree = rfGrid$ntree[i])

 # Model evaluation
 rfMetrics <- evaluate_model(rfModel, testData)

 # Save the model if the F1-measure is better than the previous ones
 if (rfMetrics$f1 > best_rf_f1) {
 best_rf_f1 <- rfMetrics$f1
 best_rf_model <- rfModel
 }
}
cat("Random Forest - F1-measure:", best_rf_f1, "\n")

运行时出现错误及警告:

Error in if (rfMetrics$f1 > best_rf_f1) { : 
  missing value where TRUE/FALSE needed
In addition: Warning message:
In randomForest.default(m, y, ...) :
  The response has five or fewer unique values.  Are you sure you want to do regression?

错误原因分析

  1. 回归任务误判:将crop_name转成数值后,randomForest默认将其视为连续变量,执行回归任务而非分类任务。回归模型的预测结果是连续数值,后续转换为因子时会出现不匹配,导致confusionMatrix计算失败,f1值变为NA,引发判断条件的错误。
  2. 因变量类型错误:分类任务要求因变量是因子类型,数值类型会触发回归模式,这就是警告信息的来源。

修正后的代码

library(caret)
library(randomForest)

# 保留因变量的因子类型(核心修正:不转成数值,或转后再转回因子)
mydata$crop_name <- factor(mydata$crop_name, levels = c("Guar", "Bajra"))

# 划分训练集和测试集
set.seed(123)
trainIndex <- createDataPartition(mydata$crop_name, p = 0.8, list = FALSE)
trainData <- mydata[trainIndex, ]
testData <- mydata[-trainIndex, ]

# 模型评估函数(适配分类任务的预测结果)
evaluate_model <- function(model, testData) {
  predictions <- predict(model, testData, type = "class")
  confusionMatrix <- confusionMatrix(data = predictions,
                                     reference = testData$crop_name,
                                     positive = "Bajra") # 明确正类别
  precision <- confusionMatrix$byClass['Pos Pred Value']
  recall <- confusionMatrix$byClass['Sensitivity']
  f1 <- 2 * precision * recall / (precision + recall)
  return(list(precision = precision, recall = recall, f1 = f1))
}

# 定义超参数网格
rfGrid <- expand.grid(mtry = c(2, 3, 4),
                      ntree = c(500, 1000, 1500))

best_rf_f1 <- 0
target_f1 <- 0.9 # 目标F1阈值

# 超参数迭代搜索
for (i in 1:nrow(rfGrid)) {
  # 训练分类随机森林模型
  rfModel <- randomForest(crop_name ~ ., 
                          data = trainData,
                          mtry = rfGrid$mtry[i],
                          ntree = rfGrid$ntree[i],
                          importance = TRUE)
  
  # 评估模型
  rfMetrics <- evaluate_model(rfModel, testData)
  
  # 更新最优模型
  if (rfMetrics$f1 > best_rf_f1) {
    best_rf_f1 <- rfMetrics$f1
    best_rf_model <- rfModel
    best_params <- rfGrid[i, ]
    
    # 达到目标精度则提前终止
    if (best_rf_f1 >= target_f1) {
      cat("达到目标F1值,提前终止搜索\n")
      break
    }
  }
}

# 输出结果
cat("最优随机森林模型 - F1值:", best_rf_f1, "\n")
cat("最优超参数: mtry =", best_params$mtry, ", ntree =", best_params$ntree, "\n")

关键修正说明

  • 因变量类型修正:将crop_name设置为因子类型,确保randomForest执行分类任务,避免回归模式的误判。
  • 评估函数适配:分类模型的预测结果是因子,无需额外转换,直接传入confusionMatrix,同时明确正类别(如"Bajra")。
  • 提前终止逻辑:增加目标F1阈值判断,一旦达到90%则停止超参数搜索,提升效率。
  • 参数记录:保存最优超参数,方便后续复现。

内容的提问来源于stack exchange,提问作者psysky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 12:17:03