使用SpatialML训练地理加权随机森林时遇'closure不可子集化'错误
地理加权随机森林grf.bw函数训练集报错问题排查与解决
问题描述
使用SpatialML包的grf.bw函数为训练集计算地理加权随机森林的带宽时,出现以下错误:
Error in dframe[DepVarName] : object of type 'closure' is not subsettable
使用完整数据集时该函数可正常运行,但拆分出训练集后触发报错。完整代码与示例数据集如下:
完整代码
library(GWmodel) library(sp) library(raster) library(SpatialML) library(terra) library(caret) library(doParallel) wd = "path/" block.data = read.csv(paste0(wd, "block.data.csv")) Coords<-block.data[ ,1:2] # convert lc column (categorical variable) to dummy variables df_dummies <- model.matrix(~ factor(lc) - 1, data = block.data) # merge the dummy variables with the original data frame block.data <- cbind(block.data, df_dummies) # remove the original lc variable block.data$lc <- NULL colnames(block.data)[7:9] = c("lc30", "lc50", "lc60") eq1 = ntl ~ pop + tirs + agbh + lc30 + lc50 + lc60 set.seed(1123) samp <- sample(nrow(block.data), 0.80 * nrow(block.data)) train <- block.data[samp, ] Coords_train <- train[ ,1:2] test <- block.data[-samp, ] Coords_test <- test[ ,1:2] no_cores <- detectCores() - 1 cl = makePSOCKcluster(no_cores) registerDoParallel(cl) # define the control trControl = trainControl(method = "repeatedcv", number = 3, search = "grid", savePredictions = FALSE) rf_default = train(eq1, data = train, method = "rf", metric = "Rsquared", trControl = trControl) print(rf_default) # Search best mtry set.seed(1234444) tuneGrid <- expand.grid(.mtry = c(2:6)) rf_mtry <- train(eq1, data = train, method = "rf", metric = "Rsquared", tuneGrid = tuneGrid, trControl = trControl, importance = TRUE, nodesize = 10, ntree = 500) best_mtry <- rf_mtry$bestTune$mtry # search best maxnodes tuneGrid = expand.grid(.mtry = best_mtry) best.rsq <- -1 best.maxnodes <- 0 for (maxnodes in c(5:15)){ set.seed(3455556) rf_maxnode = train(eq1, data = train, method = "rf", metric = "Rsquared", tuneGrid = tuneGrid, trControl = trControl, importance = TRUE, nodesize = 10, maxnodes = maxnodes, # tuneLenght = 50, ntree = 500) rsq <- rf_maxnode$finalModel$rsq if (rsq > best.rsq) { best.rsq <- rsq best.maxnodes <- maxnodes } } # search best ntree best.ntree <- -1 best.rsq <- -1 for (ntree in seq(from = 500, to = 2000, by = 500)) { set.seed(67777789) rf_maxtrees = train(eq1, data = train, method = "rf", metric = "Rsquared", tuneGrid = tuneGrid, trControl = trControl, importance = TRUE, nodesize = 10, maxnodes = best.maxnodes, ntree = ntree) rsq <- rf_maxtrees$finalModel$rsq if (rsq > best.rsq) { best.rsq <- rsq best.ntree <- ntree } } abw = grf.bw(eq1, train, kernel = "adaptive", coords = Coords_train, bw.min = 10, bw.max = 11, step = 1, trees = best.ntree, mtry = best_mtry, importance = "impurity", nthreads = 3, forests = FALSE, weighted = FALSE) abw$Best.BW
示例数据集
block.data = structure(list(x = c(4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L, 4517800L), y = c(4308200L, 4307800L, 4307400L, 4307000L, 4306600L, 4306200L, 4305800L, 4305400L, 4305000L, 4304600L, 4304200L, 4303800L, 4303400L, 4303000L, 4302600L, 4302200L, 4301800L, 4301400L, 4301000L, 4300600L), ntl = c(58.661979675293, 58.436840057373, 55.8877563476562, 51.9307441711426, 52.9197845458984, 58.1713027954102, 59.4091491699219, 58.0057525634766, 62.3850288391113, 43.693775177002, 32.7657432556152, 38.814208984375, 45.2988662719727, 30.7070808410645, 12.8714799880981, 12.8714799880981, 13.5219354629517, 23.7446193695068, 37.4298362731934, 46.3565788269043), pop = c(75.9549713134766, 77.1868209838867, 77.5336608886719, 79.3608703613281, 82.8243789672852, 86.7496871948242, 90.5956954956055, 92.8819274902344, 92.3746337890625, 87.0225830078125, 80.3043441772461, 84.9410400390625, 85.2942810058594, 83.6485595703125, 61.1035919189453, 40.2169418334961, 53.4071769714355, 76.6943511962891, 80.3962097167969, 80.990608215332), tirs = c(29.3157043457031, 29.6056385040283, 29.3482208251953, 29.9990634918213, 30.0760860443115, 30.7479610443115, 32.0067825317383, 32.5420265197754, 33.4829483032227, 34.0894584655762, 34.0738372802734, 33.5429801940918, 34.0574531555176, 35.3299293518066, 34.9521026611328, 35.1631278991699, 35.4775505065918, 34.7371597290039, 33.3271560668945, 34.1149940490723), agbh = c(4.38038444519043, 5.61569929122925, 6.89490604400635, 6.30956649780273, 6.12616586685181, 6.96545696258545, 6.16812896728516, 1.98371779918671, 1.08961737155914, 0.348455667495728, 0.0777057632803917, 0.0572107657790184, 0.53607851266861, 0.362500905990601, 0.0665311068296432, 0.138985157012939, 0.217744708061218, 0.737295210361481, 3.04893350601196, 1.89484882354736), lc = c(50L, 50L, 50L, 50L, 50L, 50L, 50L, 50L, 30L, 60L, 30L, 60L, 50L, 60L, 30L, 30L, 30L, 50L, 50L, 60L)), class = "data.frame", row.names = c(NA, -20L))
错误原因
报错的核心原因是变量名与已加载的函数重名:
- 加载的
caret包中包含名为train的模型训练函数; - 将拆分出的训练集数据框命名为
train,导致R执行grf.bw(eq1, train, ...)时,优先将train识别为caret::train函数(闭包类型),而非自定义的数据框; - 函数无法执行子集化操作(
[),因此触发object of type 'closure' is not subsettable错误。
使用完整数据集时未报错,是因为完整数据集的变量名block.data未与任何加载的函数重名,R能正确识别为数据框。
解决方案
将训练集数据框的变量名修改为不与现有函数冲突的名称,比如train_data,同时替换代码中所有引用该训练集的位置:
修改后的关键代码片段
# 拆分数据集时重命名训练集 train_data <- block.data[samp, ] Coords_train <- train_data[ ,1:2] # 后续所有引用训练集的地方替换为train_data rf_default = train(eq1, data = train_data, method = "rf", metric = "Rsquared", trControl = trControl) rf_mtry <- train(eq1, data = train_data, method = "rf", metric = "Rsquared", tuneGrid = tuneGrid, trControl = trControl, importance = TRUE, nodesize = 10, ntree = 500) # ...(中间循环部分同样替换train为train_data) # 最后调用grf.bw时使用train_data abw = grf.bw(eq1, train_data, kernel = "adaptive", coords = Coords_train, bw.min = 10, bw.max = 11, step = 1, trees = best.ntree, mtry = best_mtry, importance = "impurity", nthreads = 3, forests = FALSE, weighted = FALSE)
修改后,R能正确识别训练集为数据框,grf.bw函数即可正常执行。
内容的提问来源于stack exchange,提问作者Nikos
相关产品推荐
相关产品推荐

