首页 > 解决方案 > 嵌套在for循环中的if语句在R中不起作用?

问题描述

threshold <- .3
l <-  list()

for(i in 1:length(mitochondrial_genes)) {
  if(i < length(mitochondrial_genes)) {
    for(j in (i+1) : length(mitochondrial_genes)) {
      a <- cor.test(mitochondrial_genes[,i], mitochondrial_genes[,j])
      if(grepl("*",names(mitochondrial_genes)[i])|grepl("*",names(mitochondrial_genes)[j])) {
        if(a$estimate > threshold){
          l <- c(l, list(c(names(mitochondrial_genes)[i], names(mitochondrial_genes)[j],a$estimate)))
        }
      }
    }
  }
}

线粒体基因是一个大数据集,由代表基因的列组成。一些基因名称(列名)旁边有 * 符号。我本质上想返回一个满足相关性测试最小阈值的基因对列表。

代码成功运行,但它生成了所有可能的对,而不仅仅是那些至少有一个基因名称旁边带有 * 的基因对。基本上,这部分代码似乎是问题所在:

if(grepl("*",names(mitochondrial_genes)[i])|grepl("*",names(mitochondrial_genes)[j]))

我做错什么了吗?当我在终端上测试 if 语句时,它是孤立地工作的,并且代码似乎正在生成所有对,而不是根据令人困惑的 if 语句过滤它们。

这是一个线粒体基因的例子。

在此处输入图像描述

标签: rfor-loopif-statementgrepl

解决方案


列选择问题是由于您的正则表达式模式。这与正则表达式密切相关,以选择以 A 开头的字符串,不包含星号或井号,尽管在该问题*中它既是倒置的(不存在与存在),也是许多规则之一。

在这种情况下,有两种选择:

### wrong
grepl("*", c("a","a*"))
# [1] TRUE TRUE

### right
grepl("\\*", c("a","a*"))
# [1] FALSE  TRUE
grepl("[*]", c("a","a*"))
# [1] FALSE  TRUE

解释:

  • *在正则表达式中的意思是“零个或多个”,但更重要的是…… “前面的字符/类/组”;将此与+表示“一个或多个”进行比较,也需要在前面加上一些东西
  • 通常,正则表达式中的“任何东西”用 表示.*,其中.表示“任何字符”*仍然表示 0 或更多
  • 因为你想要文字星号,你要么需要转义它(\\*在 R 中),要么让它成为一个 class [*],其中括号内的大多数特殊字符失去了它们的含义(例外:^, -, 并且]可以按字面意思包含,但需要完成照顾和限制)

还有一些其他注意事项:

  • 您对每一对都运行测试,即使您只想要其中至少一个名称作为星号的那些;效率低下,如果您的数据“很大”,那么这只是在浪费时间(和资源);最好在运行测试之前确定要执行哪些测试

  • 不要在语句中使用|or ,只使用or ; 原因:&if||&&

    1. |/对长度为 0 或更大的&逻辑向量进行操作,而if 需要恰好长度为 1;如果你使用这些向量变体,那么你真的应该在条件向量和;之间使用anyall或其他一些聚合函数。if

    2. 如果你的条件是长度为 1,那么在你的编程风格中是声明性的,并使用 always-length-1 and/or操作符,&&并且||;

    3. 有条件的短路:&&/||支持它,&/|不要......试试这个看看这意味着什么:

      TRUE || stop("oops")
      TRUE | stop("oops")
      

combn我通过使用以下内容并过滤可能的组合来修复第一个项目符号。第二,我在向量上| 正确使用(不是在if语句中),if不需要。

您的示例数据图像(请提供可用的东西,而不是图像)不代表您的意思(*名称中没有),因此我将生成一些假数据并运行假测试来演示配对机制。

set.seed(42)
dat <- data.frame(a1=runif(5), b1=runif(5), "a1*"=runif(5), "b1*"=runif(5), check.names=FALSE)
dat
#      a1    b1   a1*   b1*
# 1 0.915 0.519 0.458 0.940
# 2 0.937 0.737 0.719 0.978
# 3 0.286 0.135 0.935 0.117
# 4 0.830 0.657 0.255 0.475
# 5 0.642 0.705 0.462 0.560

(在combn这里使用效果很好,因为测试是对称的:cor.test(a, b)与 相同cor.test(b, a)。如果测试是定向/不对称的,那么可以使用expand.grid(names(dat), names(dat))。)

这是预定义配对的一种方法:

pairs <- as.data.frame(t(combn(names(dat), 2)))
pairs
#    V1  V2
# 1  a1  b1
# 2  a1 a1*
# 3  a1 b1*
# 4  b1 a1*
# 5  b1 b1*
# 6 a1* b1*
pairs <- pairs[grepl("[*]", pairs$V1) | grepl("[*]", pairs$V2),]
pairs
#    V1  V2
# 2  a1 a1*
# 3  a1 b1*
# 4  b1 a1*
# 5  b1 b1*
# 6 a1* b1*

现在我们可以运行测试:

pairs$estimate <- mapply(function(i, j) cor.test(dat[,i], dat[,j])$estimate,
                         pairs$V1, pairs$V2)
pairs
#    V1  V2 estimate
# 2  a1 a1*   -0.611
# 3  a1 b1*    0.901
# 4  b1 a1*   -0.655
# 5  b1 b1*    0.685
# 6 a1* b1*   -0.303

threshold <- 0.3
pairs[pairs$estimate > threshold, ]
#   V1  V2 estimate
# 3 a1 b1*    0.901
# 5 b1 b1*    0.685

推荐阅读