R中的循环条件

condition in loop in R

我有一个相对简单的问题,我无法应用我在 Internet 上找到的解决方案。假设我们有:

set.seed(20)

data <- data.frame(month = rep(month.name, 25), 
a = rnorm(300, 0, 1), b = runif(300, 0, 7.2))

我想使用循环计算 ab 列之间方差的 f 检验 [=21] 中的每个月=]月。这是我通过使用完成的:

# create some empty vectors to fill in later
pval <- as.double()
ftest <- as.double()
month <- as.character()

# looping through the months

for (i in unique(data$month)){
  print(i)
  # sh.1 <- shapiro.test(data$a[data$month==i])
  # sh.1[2] > 0.05 # apply log if it's smaller than 0.05
  # sh.2 <- shapiro.test(data$b[data$month==i])
  # sh.2[2] > 0.05 # apply log if it's smaller than 0.05
  var.t <- var.test(data$a[data$month==i], data$b[data$month==i])
  f <- round(var.t[[1]],2)
  p <- round(var.t$p.value,2)
  ftest <- append(ftest, f)
  pval <- append(pval, p)
  month <- append(month, i)
}

不过,据我所知,f-test对正态分布非常敏感。因此,我计划在循环中使用一个条件,如果 shapiro 检验的 p 值小于 0.05,则需要对数据进行 log 转换;然后它将用于f-test。

通常情况下,我会使用 ifelse 条件,但我不太确定如何在这里使用它。 请问有什么帮助吗?

我相信下面的代码可以满足您的需求。它使用 *apply 循环,而不是 for 循环,以使代码更具可读性(我认为)。

首先,我将重新创建数据并确保 a 列全部为正值。

set.seed(20)

data <- data.frame(month = rep(month.name, 25), 
                   a = rnorm(300, 0, 1), b = runif(300, 0, 7.2))

data$a <- abs(data$a)

现在,我不再循环遍历 month 的唯一值,而是将 data.frame 拆分为该变量。像这样,结果列表中的每个 df sp 已经是每个月所有行的 df。

sp <- split(data, data$month)
sp <- sp[order(order(month.name))]

如果需要,数据会在这里 log 转换。

sp <- lapply(sp, function(DF){
  if(shapiro.test(DF[["a"]])$p.value < 0.05) DF[["a"]] <- log(DF[["a"]])
  if(shapiro.test(DF[["b"]])$p.value < 0.05) DF[["b"]] <- log(DF[["b"]])
  DF
})

还有lapply你想要的测试,var.test,所有这些data.frame。

vartest_list <- lapply(sp, function(DF){
  var.t <- var.test(DF[["a"]], DF[["b"]])
  list(f = var.t[[1]], 
       p.value = var.t$p.value, 
       month = as.character(DF[["month"]][1]))
})

最后,将提取函数 [[ 应用于测试结果是一件简单的事情。这是可行的,因为假设测试 class "htest" 的 R return 对象中的函数只是列表。最后一个提取循环被注释掉了。

ftest <- sapply(vartest_list, '[[', 'f')
pval <- sapply(vartest_list, '[[', 'p.value')
#month <- sapply(vartest_list, '[[', 'month')