【问题标题】:Looping over columns with rms::Predict使用 rms::Predict 遍历列
【发布时间】:2020-08-11 19:12:42
【问题描述】:

我正在编写一个函数来迭代循环遍历字符向量的每个元素,做一些事情,并将每个输出附加到适当的列表中。在循环中,我正在做的一件事是使用我的字符列表中的第 i 个元素作为它的参数。但我收到以下错误: Error in Predict(model_fit,vars[i]) : predictor(s) not in model: c("[","vars","i") 在对其进行了一些研究之后,我尝试创建一个数据承诺,以便通过修改我的函数来引用尚未评估的 vars 向量的第 i 个元素:Predict(model_fit,substitute(vars[i],env = as.list(vars)) 输出关于预测器的类似错误消息(s) 不在模型中。关于如何正确编码以便Predict() 函数准确引用我想要的向量元素的任何线索?

这是一个可重现的例子:

data(iris)
library(rms)

iris$binomial_species <- ifelse(iris$Species=='setosa',1,0)
vars <- colnames(iris)

dd <- datadist(iris)
options(datadist='dd')

for (i in seq(length(vars))) {
  fit <- lrm(binomial_species~Sepal.Length+Sepal.Width+Petal.Length+Petal.Width,data = iris)
  Predict(fit,substitute(vars[i],env=as.list(vars))
}

【问题讨论】:

    标签: r


    【解决方案1】:

    如果要对列名使用字符值,请使用name= 参数。所以这些都是一样的

    Predict(fit, Sepal.Length)
    Predict(fit, name="Sepal.Length")
    myvar <- "Sepal.Length"
    Predict(fit, name=myvar)
    

    所以在你的循环中你可以做

    for (i in seq(length(vars))) {
      fit <- lrm(binomial_species~Sepal.Length+Sepal.Width+Petal.Length+Petal.Width,data = iris)
      Predict(fit, name=vars[i])
    }
    

    这里不需要substitute()或任何非标准评估。

    【讨论】:

    • 感谢您的回复!我认为这给了我我需要的东西
    • 假设我想要两个变量在我的 Predict() 函数中变化。但是第二个变量(我们称之为Variable2)将始终相同。函数的语法是:Predict(fit, name = c(vars[i],"Variable2")?
    【解决方案2】:

    一种选择是建立对Predicteval 的调用。您没有将结果存储在任何地方,因此您应该将Predict 的结果放在一个列表中。最简单的方法是lapply 而不是循环。此外,您不需要在每次循环时都运行 fit。最后,您不能遍历所有 vars,因为它们包括“物种”(不在您的模型中)和“binomial_species”(因变量):

    library(rms)
    
    iris$binomial_species <- ifelse(iris$Species=='setosa', 1, 0)
    
    fit <- lrm(binomial_species ~ Sepal.Length + Sepal.Width + Petal.Length + 
                                  Petal.Width, data = iris)
    
    result <- lapply(colnames(iris)[-c(5:6)], function(var){
      eval(as.call(list(quote(Predict), x = fit, as.name(var))))
    })
    
    str(result)
    #> List of 4
    #>  $ :Classes ‘Predict’ and 'data.frame':  200 obs. of  7 variables:
    #>   ..$ Sepal.Length: num [1:200] 4.6 4.61 4.63 4.64 4.65 ...
    #>   ..$ Sepal.Width : num [1:200] 3 3 3 3 3 3 3 3 3 3 ...
    #>   ..$ Petal.Length: num [1:200] 4.35 4.35 4.35 4.35 4.35 4.35 4.35 4.35 4.35 
    #>   ..$ Petal.Width : num [1:200] 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 ...
    #>   ..$ yhat        : num [1:200] -18.3 -18.2 -18.2 -18.1 -18.1 ...
    #>   ..$ lower       : num [1:200] -429 -425 -422 -419 -415 ...
    #>   ..$ upper       : num [1:200] 392 389 386 382 379 ...
    #>   ..- attr(*, "out.attrs")=List of 2
    #>   .. ..$ dim     : Named int [1:4] 200 1 1 1
    
    #> (...etc)
    

    【讨论】:

    • 感谢您的回复。你的批评是对的。但是,可重现的示例是我正在做的一个极其简化的版本,因此,我真的只是创建它来复制错误消息。实际上,我正在存储我的Predict() 结果,并且每次都需要重新拟合我的模型。
    • @cliftjc1 很公平。 “建立呼叫”方法对您有用吗?
    • lapply 系列函数可能是编写循环的不错选择。您能否详细说明eval() 函数的逻辑?
    • 请原谅我的无知,我对名称的“建立呼叫”方法不熟悉
    • @cliftjc1 as.call 部分允许您将语言对象列表转换为对函数的调用。我们将函数名称Predict 作为列表中的第一个参数,然后将任何后续函数参数作为列表中的命名项。然后我们将其转换为as.call 的调用,最后使用eval 或评估该调用。尽管这可行,但它并不像@MrFlick 的回答那么简单和惯用(我不知道您可以使用name = ),尽管我可能会将我的回答中的lapply 部分作为您最终工作流程的一部分跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-15
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多