替代 for 和 ifelse 循环 - 确定元素是否位于生成的置信区间内

Alternative to for and ifelse loops - determining whether elements lie within generated confidence intervals

我正在尝试重写我的代码以不包含任何 for 循环或 ifelse 循环。目的是提取包含 0 和 1 的矩阵,具体取决于变量 mu 和变量 cinterval - 如果 y0 落在第 95 个 CI,而 0 y0 落在第 95 个 CI 内,对于 y1 也是如此。对于多个模块,将对 y0 和 y1 重复此操作。

mu 包含 y0 和 y1 的值; cinterval 包含四行:

  1. lower 95th CI limit for y0
  2. upper 95th CI limit for y0
  3. lower 95th CI limit for y1
  4. upper 95th CI limit for y1

cinterval 可以编程为具有任意数量的模块:

cinterval.fn <- function(y0y1modules) {
  matrix(c(y0results, y1results) nrow=4, ncol=no.of.modules, byrow=T) #simplified from true code
  rownames(cinterval) <- c("y0 95LCI", "y0 95UCI", "y1 95LCI", "y1 95UCI")
  colnames(cinterval) <- paste('module', 1:length(cinterval[1,]), sep='.')
  return(cinterval)
}

> cinterval
         module.1 module.2  module.3
y0 95LCI 2.434602 1.784056  1.751713
y0 95UCI 5.988160 6.519465  6.833455
y1 95LCI 3.778811 2.681708  2.805293
y1 95UCI 9.228941 9.716476 10.258412

mu 看起来像这样:

mu <- c(4, 8)
mu
y0 y1 
 4  8  

我的密码是:

incinterval.fn <- function(cov.xy, mu, n1, dr) {
  cinterval <- cintervaloutput.fn(cov.xy, mu, n1, dr) # Generates matrix with 95% CI values for y0 and y1 after modules
  y0 <- NULL   # Empty vector
  for (module.no in 1:ncol(cinterval)) {
    y0 <- cbind(y0, ifelse (cinterval[1, module.no] <= mu["y0"] || mu["y0"] <= cinterval[2, module.no], 1, 0))
  }            # If y0 inside CI, 1, else 0
  y1 <- NULL   # Empty vector
  for (module.no in 1:ncol(cinterval)) {
    y1 <- cbind(y1, ifelse (cinterval[3, module.no] <= mu["y1"] || mu["y1"] <= cinterval[4, module.no], 1, 0))
  }            # If y1 inside CI, 1, else 0
  incinterval <- rbind(y0, y1) # Combines vectors
  colnames(incinterval) <- paste('module', 1:length(cinterval[1,]), sep='.')
  return(incinterval)
}

结果 incinterval 如下所示:

     module.1 module.2 module.3
[y0]        1        1        1
[y1]        1        1        1

如果能提供更高效的编码来替换 for 和 ifelse,我们将不胜感激!我目前使用 2 个 for 和 ifeelse 循环。

示例数据:

cinterval <- data.frame(rbind(c(2.434602,1.784056,1.751713),
                                 c(5.988160,6.519465,6.833455),
                                 c(3.778811,2.681708,2.805293),
                                 c(9.228941,9.716476,10.258412)),
                   row.names = c("y0 L","y0 U","y1 L","y1 U") 
)
colnames(cinterval) <- paste0("module.",1:3)
mu <- c("y0" = 4, "y1" = 8)

您可以利用向量化并将单个值与向量进行比较

as.numeric(mu["y0"] >= cinterval[1,] & mu["y0"] <= cinterval[2,])

[1] 1 1 1

适用于 "y1"。

假设您的输入数据是这样创建的:

mu = c(y0 = 4, y1 = 8)

cinterval <-
    data.frame(names = c("y0", "y0", "y1", "y1"),
               CI = c("LCI", "UCI", "LCI", "UCI"),
               module.1 = c(2.434602, 5.988160, 3.778811, 9.228941),
               module.2 = c(1.784056, 6.519465, 2.681708, 9.716476),
               module.3 = c(1.751713, 6.833455, 2.805293, 10.258412))

然后像这样的东西可能会做你想要的:

sapply(seq_along(mu),
     function(y) {

          cis  <- cinterval[cinterval[["names"]] == names(mu)[y], -1:-2]

         apply(cis, 2, function(ci) {
              findInterval(mu[y], ci)
          })

})

我不确定您在多大程度上依赖于您的数据结构,但我提出了一种不同的方法。

如果您以其他格式构建数据集,则可以轻松地将 incinterval 的结果写入附加变量。

新数据:

cinterval <-  data.frame(year = c(0, 0, 0, 1, 1, 1),
               LCI = c(2.434602, 1.784056, 1.751713, 3.778811, 2.681708, 2.805293),
               UCI = c(5.988160, 6.519465, 6.833455, 9.228941, 9.716476, 10.258412),
               module = c(1, 2, 3, 1, 2, 3)
               )

> cinterval
  year      LCI       UCI module
1    0 2.434602  5.988160      1
2    0 1.784056  6.519465      2
3    0 1.751713  6.833455      3
4    1 3.778811  9.228941      1
5    1 2.681708  9.716476      2
6    1 2.805293 10.258412      3

现在你定义mu

mu <- c("y0" = 4, "y1" = 8)

apply 使用 findInterval 对您的行进行简短的 ifelse 条件以获取包含您的结果的新列:

cinterval$inCI <- apply(cinterval, 1, 
                        function(x) ifelse(x[1] == 0, findInterval(mu["y0"], x[2:3]), 
                                                      findInterval(mu["y1"], x[2:3]))
                        )

你的输出:

  year      LCI       UCI module inCI
1    0 2.434602  5.988160      1    1
2    0 1.784056  6.519465      2    1
3    0 1.751713  6.833455      3    1
4    1 3.778811  9.228941      1    1
5    1 2.681708  9.716476      2    1
6    1 2.805293 10.258412      3    1

请注意,如果 mu 值低于 CI,findInterval 将 return 为 0,如果在 CI 范围内,则为 1,如果低于 CI,则为 2高于 CI.

这在处理许多 years 时可能会变得很麻烦,但是可以根据需要包含尽可能多的 modules

感谢大家的建议和反馈。

我采纳了 Ape 的建议,因为它是最简单的。

代码现在用粗体文本更改为:

incinterval.fn <- function(cov.xy, mu, n1, dr) {
  cinterval <- cintervaloutput.fn(cov.xy, mu, n1, dr) # Generates matrix with 95% CI values for y0 and y1 after treatment modules (can be any number of modules))
  **incinterval <- rbind(as.numeric(mu["y0"] >= cinterval[1,] & mu["y0"] <= cinterval[2,]),
                        as.numeric(mu["y1"] >= cinterval[3,] & mu["y0"] <= cinterval[4,]))**
  colnames(incinterval) <- paste('module', 1:length(cinterval[1,]), sep='.')
  return(incinterval)
}

它没有使用 for 循环和 ifelse 循环,而是使用一种更简单的方法来回答问题,即使用比较运算符生成向量。