4

我正在数据集上运行各种建模算法。通过一次将输入变量建模到我的响应中,我获得了最好的结果,例如:

model <- train(y ~ x1 + x2 + ... + xn, ...)

一旦我训练了我的模型,我不想每次都重新运行它们,所以我一直在尝试将它们保存为.rda文件。这是一个随机森林模型的示例循环(请随意提出比循环更好的方法!):

# data_resp contains my measured responses, one per column
# data_pred contains my predictors, one per column

for (i in 1:ncol(data_resp)) {

  model <- train(data_pred_scale[!is.na(data_resp[, i]), ],
                 data_resp[!is.na(data_resp[, i]), i],
                 method = "rf",
                 tuneGrid = data.frame(.mtry = c(3:6)),
                 nodesize = 3,
                 ntrees = 500)

  save(model, file = paste("./models/model_rf_", names(data_resp)[i], ".rda", sep = ""))

但是,当我加载模型时,它将被称为model.

我还没有找到一种很好的方法来保存具有相应名称的模型,以便稍后尝试参考它。我发现可以将一个对象分配给一个字符串,如下所示:

assign(paste("./models/model_rf_", names(data_resp)[i], ".rda", sep = ""), train(...))

但是我仍然不知道如何在保存对象时引用它:

save(???, file = ...)

我不知道如何通过它的自定义名称调用该对象。

最后,即使加载也存在问题。我已经尝试过assign("model_name", load("./model.rda")),但是最终的对象,称为string最终只包含对象名称的字符串,“模型”。


环顾四周,我发现了这个问题,这似乎很相关,但我试图弄清楚如何将它应用于我的情况。

我可以创建一个列表,其中包含(我测量的响应)中每个列名的名称,data_resp然后使用lapplyto use train(),但我仍然有点坚持如何动态引用新对象名称以保留结果模型。

4

4 回答 4

3

保存模型时,保存另一个名为“name”的对象,它是您要命名的事物的字符串:

> d=data.frame(x=1:10,y=rnorm(10))
> model=lm(y~x,data=d)
> name="m1"
> save(model,name,file="save1.rda")
> d=data.frame(x=1:10,y=rnorm(10))
> model=lm(y~x,data=d)
> name="m2"
> save(model,name,file="save2.rda")

现在每个文件都知道它想要调用什么结果对象。你如何让它重新加载?加载到新环境中,并分配:

> e=new.env()
> load("save1.rda",env=e)
> assign(e$name,e$model)
> summary(m1)

Call:
lm(formula = y ~ x, data = d)

您现在可以安全地 rm 或重新使用 'e' 对象。您当然可以将其包装在一个函数中:

> blargh=function(f){e=new.env();load(f,env=e);assign(e$name,e$model,.GlobalEnv)}
> blargh("save2.rda")
> m2

Call:
lm(formula = y ~ x, data = d)

请注意,这是一件双重的坏事——首先,您可能应该将所有模型作为带有名称的列表存储在一个文件中。其次,这个函数有副作用,如果你已经调用了一个对象m2,它就会被踩到。

像这样使用assign几乎总是一个标志(dyswidt?),你应该使用一个列表来代替。

于 2013-07-21T07:55:12.690 回答
1

这个答案涉及相当多的猜测,但我认为这可能会有所帮助:

# get a vector with the column names in data_resp
modNames <- colnames( data_resp )

# create empty list
models <- as.list( NULL )

# iterate through your columns and assign the result as list members
for( n in modNames )
{
  models[[n]] <- train(data_pred_scale[!is.na(data_resp[, n]), ],  ### this may need modification, can't test without data
                 data_resp[!is.na(data_resp[, n]), n],
                 method = "rf",
                 tuneGrid = data.frame(.mtry = c(3:6)),
                 nodesize = 3,
                 ntrees = 500)
}

# save the whole bunch
save( models, file = "models.rda" )

现在,您可以仅使用load( "models.rda )这个对象检索包含所有模型的列表,并使用列表符号对它们进行寻址,无论是作为models[[1]]还是使用列名,例如。models[["first"]].

于 2013-07-21T05:15:32.670 回答
1

我认为有关使用循环执行此操作的其他答案很棒。我以此为契机最终尝试并lapply更好地理解,因为有关如何做到这一点的许多 StackOverflow 问题最终都建议使用列表而lapply不是循环。

我真的很喜欢将所有结果合并train()到一个列表中(@vaettchen 在他的循环中所做的)的想法,并且在考虑如何使用列表执行此操作时,这就是我想出的。首先,我需要列表形式的data.frame,每列一个条目。由于我并不真正使用列表,所以我一直在寻找直到尝试as.list(df),这就像一个魅力。

接下来,我想将我的 train 函数应用于测量的响应变量列表的每个元素,所以我定义了这样的函数:

# predictors are stored in data_pred
# responses are in data_resp (one per column)
# rows in data_pred/data_resp (perhaps obviously) match, one per observation

train_func <- function(y) { train(x = data_pred, y = y,
   method = "rf", tuneGrid = data.frame(.mtry = 3:6),
   ntrees = 500) }

现在我只需要使用lapply对. 我不知道如何创建一个空的占位符列表,因此感谢@vaettchen(我尝试过但没有成功):train()data_resplist_name <- list()

models <- lapply(as.list(data_resp), train_func)

太棒了,我发现models它的元素会自动命名为我的列名data_resp,这真是太棒了。我将它与shiny包结合使用,因此这将使用户非常容易从下拉列表中选择响应变量(可以存储响应变量名称)并执行以下操作:

predict(models[["resp_name"]], new_data)

我认为这比基于循环的方法好得多,而且一切都恰巧就位。我意识到这个问题明确要求以编程方式命名变量,所以如果这促使其他人以这种方式回答而不是“更大的图景”答案,我深表歉意。lapply当(至少在我看来)更好的解决方案存在时,我试图强制执行一个特定的解决方案。


奖励:我没有意识到列表可以是多维的,但在尝试它时,它们似乎可以!这更好,因为我使用了许多算法,并且可以将所有内容存储在一个大列表对象中。

 func_rf <- function(y) { train(x = data_pred, y = y,
     method = "rf", tuneGrid = data.frame(.mtry = 3),
     ntrees = 100) }

 # svmRadial method requires formula syntax to work with factors,
 # so the train function has to be a bit different
 # add `scale = F` since I had to preProcess the numeric vars ahead of time
 # and cbind to the factors. Without it, caret will try to scale the data
 # for you, which fails for factors

 func_svm <- function(y) { train(y ~ ., cbind(data_pred, y),
     method = "svmRadial", tuneGrid = data.frame(.C = 1, .sigma = .2),
     scale = F) }

 model_list <- list(NULL)
 model_list$rf <- lapply(as.list(data_resp), func_rf)
 model_list$svm <- lapply(as.list(data_resp), func_svm)

现在我可以使用列表语法引用所需的模型响应变量!

 predict(model_list[["svm"]][["response_variable"]], new_data)

对此非常满意,希望它能让代码更高效、更快,而且我真的很喜欢我最终得到的“元对象”与我必须加载的大量文件,每个模型/响应变量组合一个以后一次一个。

于 2013-07-21T15:21:35.687 回答
0

有点老问题,但仍然没有公认的答案。
据我了解,您需要以编程方式重命名变量并保存它,以便在重新加载时保留新名称。
尝试这个:

saveWithName = function(var.name, obj){
  # var.name is a string with the name of the variable you want to assign
  # obj is any kind of R object (data.frame, list, etc.) you want to rename and save
  assign(var.name, obj)
  save(list=var.name, file=sprintf("model_%s.RData", var.name))
}

saveWithName("lab1", c(1,2))
saveWithName("lab2", c(3,4))
load("model_lab1.RData")
load("model_lab2.RData")

print(lab1)
#>[1] 1 2
print(lab2)
#[1] 3 4
于 2018-04-16T15:28:22.100 回答