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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:12:15