【问题标题】:Common elements in data frames数据框中的常见元素
【发布时间】:2015-06-08 12:53:26
【问题描述】:

我有三个数据框,有很多信息和以下行名:

ENSG00000000971 ENSG00000000971 ENSG00000000971
ENSG00000004139 ENSG00000004139 ENSG00000003987
ENSG00000005001 ENSG00000004848 ENSG00000004848
ENSG00000005102 ENSG00000002330 ENSG00000002330
ENSG00000005486 ENSG00000005102 ENSG00000006047
...             ...             ...

我想要做的是找到至少 2 个数据帧中常见的所有条目(行名)。即,最终结果应该是一个列表,如下所示:

ENSG00000000971
ENSG00000004139
ENSG00000004848
ENSG00000005102
ENSG00000002330

我该怎么做呢?我试过这样做:

shared.DESeq2.edgeR = data.frame(row.names(res.DESeq2) %in% row.names(res.edgeR))
shared.DESeq2.limma = data.frame(row.names(res.DESeq2) %in% row.names(res.limma))
shared.edgeR.limma = data.frame(row.names(res.edgeR) %in% row.names(res.limma))
shared = merge(merge(shared.DESeq2.edgeR, shared.DESeq2.limma), shared.edgeR.limma)

... 其中三个res.[DESeq2/edgeR/limma] 是三个数据帧,但这需要很长时间才能运行(我什至没有让它完成,所以我不知道它是否真的有效)。我有一些代码可以为 所有三个 数据帧共有的元素执行此操作,但我也对两个或多个数据帧共有的元素感兴趣,但我不能真的找到了一个很好的方法来做到这一点。有什么想法吗?

【问题讨论】:

  • 任何数据框都可以包含重复项吗?
  • 不,任何数据框中的行名都没有重复。

标签: r dataframe bioinformatics intersection


【解决方案1】:

试试这个例子:

#dummy data, with real data we would do: res.DESeq2_rn <-row.names(res.DESeq2)
res.DESeq2_rn <- letters[1:4]
res.edgeR_rn <- letters[3:8]
res.limma_rn <- letters[c(1,3,8,10)]

#get counts
res <- table(c(res.DESeq2_rn, res.edgeR_rn, res.limma_rn))
res
# a b c d e f g h j 
# 2 1 3 2 1 1 1 2 1 

#result
names(res)[ res>=2 ]
#[1] "a" "c" "d" "h"

编辑:基准测试表明@vaettchen 的解决方案是赢家!

library(microbenchmark)
library(ggplot2)
# create a large random character vector (this takes a lot of time!)
set.seed(123)
myNames <- sapply(1:1000000,
                  function(i)paste( sample( letters, 8, replace = TRUE ), collapse = "" ))
A <- sample(myNames,1000)
B <- sample(myNames,2000)
C <- sample(myNames,3000)

#benchmarking 3 options
myBench <- microbenchmark(
  Which={
    res <- c(A,B,C)
    out1 <- unique( res[ which( duplicated( res ) ) ] ) },
  Table={ 
    res <- c(A,B,C)
    y <- table( res )
    out2 <- names( y )[ y >= 2 ] },
  Intersect={ 
    out3 <- 
      unique(
        c(intersect(A,B),
          intersect(A,C),
          intersect(B,C)))},
  times=1000)

print(myBench)
qplot(y=time, data=myBench, colour=expr) + scale_y_log10()

Unit: microseconds
      expr       min         lq       mean     median         uq       max neval cld
     Which   266.837   280.4190   527.8266   288.2680   301.2475  59255.34  1000  a 
     Table 32167.286 32739.5945 34851.2260 33072.0825 33524.2550 108176.22  1000   b
 Intersect   450.965   472.3965   667.3316   484.7725   499.8650  60266.54  1000  a 

【讨论】:

    【解决方案2】:

    另一种方法,取@zx8754的样本数据:

    # dummy data
    res.DESeq2 <- letters[ 1:4 ]
    res.edgeR <- letters[ 3:8 ]
    res.limma <- letters[ c( 1, 3, 8, 10 ) ]
    
    # combine into one vector                  
    res <- c( res.DESeq2, res.edgeR, res.limma )
    res
    [1] "a" "b" "c" "d" "c" "d" "e" "f" "g" "h" "a" "c" "h" "j"
    
    # result
    unique( res[ which( duplicated( res ) ) ] )
    [1] "c" "d" "a" "h"                  
    

    编辑

    @zx8754 的回答被接受了,出于所有充分的理由,它干净而优雅。纯粹出于我的求知欲,我研究了他和我的大样本方法之间的性能差异,发现它很有趣,可以发布它:

    # create a large random character vector (this takes a lot of time!)
    res <- rep( "x", 1000000 )
    for( i in 1:1000000) 
        res[ i ] <- paste( sample( letters, 8, replace = TRUE ), collapse = "" )
    head( res )
    [1] "vsvkljgr" "ulxhqnas" "upqqtrdk" "pynuaihp" "srjtnvqm" "mxnlytvd"
    
    # vaettchen:
    system.time( x <- unique( res[ which( duplicated( res ) ) ] ) )
     user  system elapsed 
    0.173   0.000   0.171 
    x
    [1] "zlzlwinb" "wielycpx"
    
    # zx8754
    system.time( { y <- table( res ); z <- names( y )[ y >= 2 ] } )
      user  system elapsed
    18.945   0.020  19.058 
    z
    [1] "wielycpx" "zlzlwinb"
    

    对于足够大的数据或重复调用,差异可能很重要。简要说明我的代码的作用:

    • duplicated( res ) 创建一个长度为 res 的向量,其中包含逻辑 TRUE 或 FALSE,具体取决于字符串是否重复出现
    • which( ... ) 将其转换为索引向量,其中该值为 TRUE
    • res[ ... ]在索引位置提取res的实际字符值,并
    • unique( ... ) 将每个字符值减少到只有一个外观,这是@Sajber 正在寻找的答案(据我了解)

    【讨论】:

    • 是的,基准测试表明您的方法是最快的。查看我编辑的帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-03
    • 2017-05-27
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多