有没有办法将我列表中的每个 component/element 除以对应于某个因子变量水平的值

Is there a way to divide each component/element of my list by a value that corresponds to the level of some factor variable

当 运行 metafor 中的 rma.mv 命令时,我目前遇到模型收敛问题。我已经设法弄清楚这是因为我的 R 脚本中的错误代码导致计算出的方差非常大(而且是错误的)。所以,我知道这个问题,但我不知道如何解决。下面我将概述我正在尝试做的事情、我目前是如何实现的以及我是如何找出问题的原因的:

我想做什么

我想要做的事情的要点是为我的数据集中的每个预测模型获取自举 SEE 值,并将这些值缩放到相应研究的标准均值。 (即测量的实际值)。值得注意的是,一些研究有多个模型。缩放完成如下:

(SEE/criterion 平均值)*100.

数据

structure(list(Study = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L), .Label = c("1", "2", "3", "4", "5", "6", "7"), class = "factor"), 
    Model = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 
    4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 
    4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 
    5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 
    6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 
    7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 
    8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L), .Label = c("1", "2", "3", 
    "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", 
    "15", "16", "17", "18", "19", "20", "21"), class = "factor"), 
    Residual = c(1.585838423, 10.53555743, 10.67781267, 1.22720582, 
    2.598848981, 26.94888607, 1.440304678, 15.74086952, 24.27068334, 
    11.74554852, 13.21437544, 12.81558569, 15.65125984, 0.25625278, 
    7.941652407, 5.557930412, 5.359401505, 8.537299607, 2.671115348, 
    17.34002169, 2.598006397, 1.011493647, 10.38934426, 23.80005223, 
    5.655188679, 4.878735797, 11.28737632, 1.048913043, 6.670565717, 
    6.100551281, 15.55386342, 0.452170844, 1.077426851, 4.152827648, 
    13.16037736, 4.308822184, 3.383948815, 16.53474723, 5.323566515, 
    2.386768718, 5.63280155, 3.577780725, 1.60254086, 15.74086952, 
    0.490982433, 20.16709778, 4.622970061, 1.894674528, 14.60716285, 
    1.353952437, 4.596126567, 6.579200694, 2.749886696, 7.002473325, 
    6.999046711, 5.986306941, 15.80934315, 0.028470501, 8.299180328, 
    2.372475627, 9.538286164, 4.878735797, 6.671197129, 7.172826087, 
    0.19253775, 3.098225566, 14.50304585, 0.680903636, 15.64487166, 
    2.742369838, 11.42322707, 2.365470852, 1.838235294, 9.9, 
    1.470588235, 1.041666667, 0.454545455, 22.45614035, 6.196296296, 
    9.181818182, 31.97674419, 6.607142857, 7.720588235, 15.88888889, 
    14.09090909, 2.5, 1.875, 0, 7.75, 4.6875, 6.25, 14.8, 10.88235294, 
    0, 2.121212121, 0, 9.824074074, 9.181818182, 9.186046512, 
    13.03571429, 0, 5.333333333, 13, 1.25, 14.19642857, 1.346153846, 
    5.583333333, 2.8125, -2.097428958, 1.745602165, 3.531799729, 
    4.262516915, 1.826792963, 2.963464141, -2.963464141, -2.584573748, 
    -4.50608931, -4.912043302, -5.209742896, -6.211096076, -3.775372124, 
    -4.803788904, -8.944519621, -1.146245059, 2.938076416, 4.914361001, 
    5.12516469, 4.65085639, 1.567852437, -2.437417655, -3.544137022, 
    -4.677206851, -5.441370224, -6.442687747, -1.963109354, -3.675889328, 
    -7.891963109, -4.466403162), Criterion.Mean = c(162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 
    162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 79.4, 79.4, 
    79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 
    79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 
    79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4, 79.4)), row.names = c(NA, 
138L), class = "data.frame")

我做了什么

首先,我创建了一个用于计算 SEE 的用户定义函数 SEE<- function(x){sqrt((sum(x)/(length(x)-2))^2)}

然后我为每个模型生成了 1000 个样本,并为每个样本计算了 SEE。我根据需要使用 tapply 函数来确保 SEE 是根据与特定模型对应的残差值计算的。代码如下:

Bootstrapped_SEE<- tapply(new.meta$Residual, INDEX = new.meta$Model, FUN = function (x){
  int<- lapply(1:1000, function(i) sample(x, replace = T))
  Calc.SEE<- sapply(int, SEE)
})

这个 returns 一个长度为 21 的列表(完整数据集中有 21 个模型),其中每个元素的长度为 1000(1000 个 SEE 值)。为了将这些转换为 SEE 值,我使用了以下代码:

SEE.percentage.List<-lapply(SEE_Var_List, FUN = function(i) (i/new.meta$Crtierion.Mean)*100)

问题

正如我上面所说,我想要做的是,对于列表中的每个元素(即对应于特定模型的 SEE 向量),除以相应研究的标准均值(同样可能是多个模型 - 因此列出元素 - 每个研究,所有这些都具有相同的标准均值)。刚才发生的事情是 R 只是循环向下循环列向量 Criterion.Mean 并除以第 i 个值。好消息? R 正常工作!坏消息?在第 19 个 SEE 值之后,它开始将对应于研究 1 的 SEE 值除以研究 2 的 Criterion.Mean 值。因此,我需要的是一种将我的 SEE 值除以相应研究的标准平均值的方法,其中可以有多个模型用于给定研究(即,列表的多个元素具有相同的标准平均值)。

解决方案?

概念性的解决方案是以某种方式 link 列表中的每个元素到一个特定的研究,然后用代码将与研究相关的所有元素除以相应的 Criterion.Mean 值。我最初认为某种 tapply 函数可以在这里工作,但很快意识到该列表独立于包含的数据框,因此提供 study 作为索引可能不起作用。

有人知道怎么做吗?我很迷茫,因为这超出了我目前的编码能力。我了解问题及其发生的原因,但我不知道如何从语法上解决这个问题。预先感谢您的所有帮助。

对于以后关注此内容的任何人,以下是我使用 base R 绕过它的方法。我知道那里可能有更优雅、更流畅的解决方案,但这可以完成工作:

步骤的口头描述

  1. 首先,我创建了一个新的“子集”数据框,其中仅包含模型及其相应的 标准均值 值一次(即,我删除了重复的观察值)

  2. 接下来,我按模型对新数据框进行排序,纯粹是为了便于解释和检查。因为我一直在努力以“循环”类型的方式执行此操作,所以我先手动完成了。这最终取得了胜利,因为它允许我将循环的结果与手动计算进行交叉引用,以确保它们是正确的……我只需要确保列表元素与正确的模型相对应(即, 元素 1= 模型 1).

  3. 然后我使用 lapply 将 var 函数应用到包含缩放 SEE 值的新列表的每个元素。

  4. Walla,你现在有结果了。漂亮吗?可能不会。能不能更优雅一点?当然,它可能会。它有效吗?是的

代码

这是我使用的代码:

#Create new dataframe, and remove duplicates.

  Temp_Dat<- full.data[!duplicated(full.data$Model), ]

#Order new dataframe by model 

  Temp_Dat<- Temp_Dat[order(Temp_Dat$Model), ]

#Create list to save results of for loop.
  
  Bootstrapped_SEE_Per <- list()
  
#Run for loop. [[i]] indicates sub-element of list and [i] indicates element of vector. Therefore this is applied to each sub-element of the list using the"ith" value in the criterion mean vector. This creates a new list, with the only change being that now all SEE values are scaled by criterion mean and expressed as a %

  for( i in 1:length(Bootstrapped_SEE)){
    Bootstrapped_SEE_Per[[i]] <- (Bootstrapped_SEE[[i]]/ Temp_Dat$Criterion.Mean[i])*100
  }

#Use lapply function to calculate the variance of each element of the new list.
  
  SEE_Per_Variance<- lapply(Bootstrapped_SEE_Per, var)

希望这对将来某个时候处于类似情况的其他人有所帮助。对于那些使用 tidyverse 阅读本文的人,我相信您可以使用 purr 包中的 map2 函数。但是,我对 tidyverse 整体上很不熟悉,所以我选择了基本的 R 解决方案。

感谢所有的贡献!