【问题标题】:R - comparing two rows by columns and writing the result in a tableR - 按列比较两行并将结果写入表中
【发布时间】:2016-05-14 14:42:56
【问题描述】:

我是 R 新手,我的问题的解决方案可能非常简单,但现在我无法做到...... 我想按列比较数据框中的行。每列数据是一个字母(核苷酸碱基):

seq1 A C T G T
seq2 A C G G G
seq3 A G G C A
...

我想按列比较数据集中的所有行。我想得到的结果是比较中的 TRUE 和 FALSE 简单的 1 或 0,也写成表格的形式。所以它看起来像这样:

seq1_seq2 1 1 0 1 0
seq1_seq3 1 0 0 0 0
seq2_seq3 1 0 1 0 0
...

我的 R 语言水平太低,无法写出有用的东西。但是,我设法发现

ifelse(data[1,]==data[2,], 1, 0) 

虽然没有显示比较了哪些行(没有 seq1_seq2 列),但几乎返回了我需要的内容。 我将不胜感激有关此问题的任何帮助。当然,最需要完整解决方案的示例,但我也将不胜感激有关如何解决此问题的任何建议。

提前谢谢你!

【问题讨论】:

    标签: r seq


    【解决方案1】:

    在数据框中按行存储序列是错误的。您应该按列存储序列,或者,如果按行存储它们,至少在矩阵而不是数据框中进行。下面我假设您使用矩阵。您可以使用as.matrix 函数将数据框转换为矩阵。

    如果你想避免循环,你应该使用combn来完成这样的任务

    > a
         [,1] [,2] [,3] [,4] [,5]
    seq1 "A"  "C"  "T"  "G"  "T" 
    seq2 "A"  "C"  "G"  "G"  "G" 
    seq3 "A"  "G"  "G"  "C"  "A" 
    
    > compare = t(combn(nrow(a),2,FUN=function(x)a[x[1],]==a[x[2],]))
    > rownames(compare) = combn(nrow(a),2,FUN=function(x)paste0("seq",x[1],"_seq",x[2]))
    
    > compare
              [,1]  [,2]  [,3]  [,4]  [,5]
    seq1_seq2 TRUE  TRUE FALSE  TRUE FALSE
    seq1_seq3 TRUE FALSE FALSE FALSE FALSE
    seq2_seq3 TRUE FALSE  TRUE FALSE FALSE
    

    将布尔值转换为整数(如果你真的需要的话):

    storage.mode(compare) = "整数"

    【讨论】:

    • 即使在进行 n 平方计算时,此解决方案也快得多。所以,我会用这个而不是双循环。
    • @Gopala 就渐近速度而言,所有三个解决方案都是相同的。如果 n 是序列中的元素数(示例中为 5),则计算量为 O(n)。
    • 是的,我明白....这是 n 平方运算。但是,combn 执行循环的效率要高得多,这正是我试图提出的观点。
    • 感谢大家的回复!伙计们,你们真棒!我已经测试了所有解决方案并将 user31264 响应标记为一个解决问题,因为它是最快的。 Dominic 的回答在小型测试数据集上效果很好。然而,我在大约 1800 个序列上尝试了这个,Gopala 的脚本在 20 分钟内消耗了我所有的 16Gb RAM,导致 R 会话崩溃。正如 Gopala 所注意到的,User31264 的解决方案要快得多。在 1800 seq 数据集上,它在 5 分钟内生成了超过 500Mb 的结果文件。再次感谢所有回复的人!
    【解决方案2】:

    在这种情况下,由于您希望完成所有 n 平方比较,因此以这种方式循环是一种选择:

    result <- list()
    for (i in 1:(nrow(df) - 1)) {
        for (j in (i + 1):nrow(df)) {
          result[[paste(row.names(df)[i], row.names(df)[j], sep = '_')]] <- as.integer(df[i, ] == df[j, ])
        }
    }
    as.data.frame(do.call(rbind, result))
    

    结果输出如下:

              V1 V2 V3 V4 V5
    seq1_seq2  1  1  0  1  0
    seq1_seq3  1  0  0  0  0
    seq2_seq3  1  0  1  0  0
    

    当然,对于较大的数据集,这将非常慢。

    【讨论】:

    • for i in 1:(nrow(df)-1);对于 j in (i+1):nrow(df)
    • 我只是在进行编辑时注意到我在避免额外计算方面的错误。
    【解决方案3】:

    与 Gopala 的方法有些不同...可能有更简单的方法可以到达那里,但它是:

    options(stringsAsFactors = FALSE)
    myData <- data.frame(n1=c("A","A","A"),n2=c("C","C","G"),
                         n3=c("T","G","G"),n4=c("G","G","C"),n5=c("T","G","A"))
    rownames(myData) <- paste0("seq",1:3)
    
    # Generate all combinations for comparisons
    compar <- apply(combn(rownames(myData),2),2,paste0)
    
    # Create a temporary list having pairs of rows
    myList <- apply(compar, 2, function(r) myData[r,])
    names(myList) <- apply(combn(rownames(myData),2),2,paste0,collapse="_")
    
    # Compare the two rows for each element in the list
    results <- t(sapply(myList, function(x) as.numeric(x[1,]==x[2,])))
    colnames(results) <- colnames(myData)
    
    results
    
              n1 n2 n3 n4 n5
    seq1_seq2  1  1  0  1  0
    seq1_seq3  1  0  0  0  0
    seq2_seq3  1  0  1  0  0
    

    【讨论】:

      【解决方案4】:

      您可以使用此代码(它使用@Dominic Comtois 的答案中的myData):

      m <- combn(nrow(myData),2)
      
      result <- sapply(myData,function(C) {z=C[m];z[c(TRUE,FALSE)]==z[c(FALSE,TRUE)]})
      #       n1    n2    n3    n4    n5
      #[1,] TRUE  TRUE FALSE  TRUE FALSE
      #[2,] TRUE FALSE FALSE FALSE FALSE
      #[3,] TRUE FALSE  TRUE FALSE FALSE
      

      它是如何工作的:

      1. combn 生成所有可能的行索引对
      2. sapply 循环遍历 myData 的每一列
      3. 对于每一列,获取矩阵m 的向量模拟,其中行索引由myData 中的值替换
      4. 该向量的奇数元素包含第一行,偶数元素包含第二行,因此我们可以使用位掩码 c(TRUE,FALSE) 和 c(FALSE,TRUE) 来比较奇数/偶数元素。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-10
        • 1970-01-01
        • 1970-01-01
        • 2014-05-16
        • 1970-01-01
        • 1970-01-01
        • 2021-03-31
        • 1970-01-01
        相关资源
        最近更新 更多