从lapply对象中提取循环元素

3
简而言之:有没有一种方法可以遍历下面描述的lapply对象allModelsResults的每个元素?
意思是,例如allModelsResults$'1'给我对象的第一个元素。接下来allModelsResults$'2'将是第二个元素。我想创建一个for循环来提取每个元素,运行一些命令并存储结果。
详细说明如下...
我有以下代码,使用“knn”在多个模型规范中运行简单的ML模型。 模型规范存储在allModelList中,所有结果都存储在allModelsResults中。
所有模型列表中的单个模型如下:
y ~ x1 + x2 + x3

或者

y ~ x1 + x5 + x4

等等,简而言之,模型规格的一系列组合

allModelsResults <- lapply(allModelsList, function(x) train(x,       data=All_categories_merged_done,method = "knn"))

我现在希望能够逐个提取每个元素(每个模型的结果)以进行分析。例如,我可以手动选择:allModelsResults$'1' 来获取第一个模型的结果,或者 allModelsResults$'5' 来获取第五个模型的结果等等。
理想情况下,我希望能够通过循环逐个选择这些元素,并运行一系列命令。
请帮忙提供有关如何从 allModelsResults 对象中提取元素的任何帮助! 我有大约50个模型规范,因此我需要创建一个循环或类似的东西来自动逐个提取。
具体来说,为了与社区分享,对于每个元素,我都想逐个执行此操作,针对每个模型。
这里是一个示例,我正在提取模型1(这显然不起作用):
aggregate_results <- NULL

for(z in 1:length(categories)){
element_number_ID <- (element_number[z])

element_number_ID 应该等于 '1' 才能提取正确的模型。

    model_1_result <- allModelsResults$'1'

    ResultsTestPred <- predict(model_1_result, testing_data)
    results_to_store <- confusionMatrix(ResultsTestPred, testing_data $outcome)

aggregate_results  <- rbind(aggregate_results, results_to_store)

}

results_to_store 的一个元素的输出如下:

混淆矩阵和统计信息

      Reference

预测 0 1 0 14 2 1 4 19

           Accuracy : 0.8462          
             95% CI : (0.6947, 0.9414)
No Information Rate : 0.5385          
P-Value [Acc > NIR] : 0.00005274      

              Kappa : 0.688           

Mcnemar的检验P值:0.6831

        Sensitivity : 0.7778          
        Specificity : 0.9048          
     Pos Pred Value : 0.8750          
     Neg Pred Value : 0.8261          
         Prevalence : 0.4615          
     Detection Rate : 0.3590          

检测普遍性:0.4103 平衡准确率:0.8413
   'Positive' Class : 0       

我希望为每个元素/模型保存准确性值,这样我就可以比较不同模型的规格以确定其准确性。感谢您提供的任何见解!

如果您有一个结果列表,请使用*apply的形式来处理它,例如:lapply(allModelsResults, predict, testing_data) - Rui Barradas
谢谢Rui Barradas,我该如何存储特定的结果?例如,从我的results_to_store中? - Peter Alexander
1
那要看情况。如果提取的是一个固定长度的向量,我会使用sapply。它将返回一个向量、矩阵或类似的对象,这些对象以整洁的格式易于进一步处理。否则,我会使用lapply并将提取的内容保存在列表中。 - Rui Barradas
3
使用 [[ 而不是 $ 来访问列表元素。这种方法对于变量也是有效的。allModelResults[[1]] 表示第一个元素,如果 i = 3,则 allModelResults[[i]] 表示第三个元素。 - Gregor Thomas
3
lapply函数始终返回一个列表,不需要称其为“lapply对象”,它只是一个列表。 - Gregor Thomas
显示剩余4条评论
1个回答

3

您似乎希望获取每个模型的预测结果和混淆矩阵。由于没有可重现的示例并且术语有些混淆,我需要进行很多猜测,但我认为我理解了您想要什么(或者足够接近)。我将向您展示如何使用lapplyMap来完成它,然后我们也可以使用for循环进行操作。

首先,在测试数据上获取预测结果。所有这些方法都是完全相同的:

# lapply way
predictions = lapply(allModelsList, predict, newdata = testingdata)

# for loop way
predictions = list()
for (i in 1:length(allModelsList)) {
  predictions[[i]] = predict(allModelsList[[i]], newdata = testingdata)
}

# manual way - just so you understand exactly what's going on
predictions = list(
  predict(allModelsList[[1]], newdata = testingdata),
  predict(allModelsList[[2]], newdata = testingdata),
  predict(allModelsList[[3]], newdata = testingdata),
  ...
)

现在,predictions是一个list,因此我们使用[[访问每个元素。第一个元素是predictions[[1]],如果我们想要定义一些变量k(例如在循环中使用),第k个元素是predictions[[k]]。我们还可以添加描述性名称并使用名称而不是索引。

同样地,我们可以计算所有的混淆矩阵:

# lapply way
conf_matrices = lapply(predictions, confusionMatrix, reference = testingdata$outcome)

# for loop way
conf_matrices = list()
for (p in 1:length(predictions)) {
  conf_matrices[[p]] = confusionMatrix(p, reference = testingdata$outcome)
}

# manual way (for illustration)
conf_matrices = list(
  confusionMatrix(predictions[[1]], reference = testingdata$outcome),
  confusionMatrix(predictions[[2]], reference = testingdata$outcome),
  ...
) 

再次,我们有一个列表。第一个混淆矩阵是conf_matrices [[1]],与上述所有相同。
希望这可以帮助我们了解如何使用lapply或for循环来创建列表。
现在,在您的问题底部,您似乎暗示了混淆矩阵的Accuracy部分。我运行了帮助页面?confusionMatrix底部的示例并查看了结果。在结果上运行str(conf_mat)向我展示它是一个列表,并且列表的overall元素是命名向量,包括Accuracy。因此,对于单个混淆矩阵cm,我们可以使用cm [“overall”] [“Accuracy”]提取准确度。我们在list部分使用[[和正常向量部分使用[。 (我们也可以使用cm $ overall [“Accuracy”]。 $适用于当我们给出精确名称时,无引号,无变量。您的许多问题似乎与尝试使用带有引号或变量的$有关。你就是不能那样做。请参见fortunes :: fortune(312))。
因此,我们可以从我们的混淆矩阵列表中提取准确性。
# I use *s*apply here so the result will be *s*implified into a vector
acc = sapply(conf_matrices, function(cm) cm[["overall"]]["Accuracy"])

acc = numeric(length(conf_matrices))
for (i in 1:length(conf_matrices)) {
  acc[i] = conf_matrices[[i]][["overall"]]["Accuracy"]
}

或者,如果您从一开始就知道您只需要准确性,我们可以直接到达目的地,而不保存中间步骤:

# apply
acc = sapply(allModelsList, function(x) {
    pred = predict(x, newdata = testingdata)
    cm = confusionMatrix(pred, reference = testingdata$outcome
    return(cm[["overall"]]["Accuracy"]
  }
)

# for循环 acc = numeric(length(allModelsList)) for (i in 1:length(allModelsList)) { # 预测模型 pred = predict(allModelsList[[i]], newdata = testingdata) # 计算混淆矩阵并求出准确率 cm = confusionMatrix(pred, reference = testingdata$outcome) acc[i] = (cm[["overall"]]["Accuracy"]) }


注:如上所述,由于没有可重现的示例,我进行了许多猜测,并且由于没有任何输入进行测试,因此没有进行任何测试。 我假设您在问题中看到的各个步骤,例如我们要对allModelResults的每个元素进行预测,都是正确的。 (如果是这样的话,fittedModels似乎比allModelResults更好的名称。)我不知道您所说的“模型规格”是什么,也不知道allModelList中有什么,但希望这足以为您提供使用列表的示例,以便您可以解决任何问题。(还可能存在括号不匹配或缺少括号等问题。) lapplysapply可以让您进行的键入量较少,但它们实际上并没有任何区别。 它们设置一个对象来保存结果,并将其填充。 如果要同时创建多个结果,则可能只需使用for循环。 而且,随着内部步骤的数量变得更长,调试for循环可能会更容易。 使用您喜欢和符合您逻辑的方法。


1
这个答案绝对棒极了。我确实习惯使用带有$符号的数据框架。感谢您如此清晰地解释每一步。我希望这对其他人也有用。 - Peter Alexander
1
请注意,使用[[[与变量在数据框中也适用。 (数据框是列表,只是具有一些额外的属性。)因此,虽然mtcars$mpgmtcars数据框中的mpg列,但如果您有一个变量col =“mpg”中的列名,则mtcars$col将无法正常工作。您可以使用mtcars [,col]mtcars [[col]]-当您想要可能多个列时,请使用[,col],当您知道只需要单个列作为向量时,请使用[[ - Gregor Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接