【问题标题】:R: Quickest way to create dataframe with an alternative to IFELSER:使用 IFELSE 的替代方法创建数据框的最快方法
【发布时间】:2017-05-09 20:54:54
【问题描述】:

我在这个帖子上有一个类似的问题: Using R, replace all values in a matrix <0.1 with 0?

但在我的情况下,我假设有更大的数据集和可变阈值。 我需要创建一个数据框,其中使用同一数据框第一列上的值从条件中检索到每个值。每一行的这些值都不同。

这是数据框的示例:

SNP        A1  A2   MAF     
rs3094315  G   A   0.172  
rs7419119  G   T   0.240  
rs13302957 G   A   0.081  
rs6696609  T   C   0.393 

这是我的代码示例:

seqIndividuals = seq(1:201)
for(i in seqIndividuals) {
  alFrequ[paste("IND",i,"a",sep="")] = ifelse(runif(length(alFrequ$SNP),0.00,1.00) < alFrequ$MAF, alFrequ$A1, alFrequ$A2)
  alFrequ[paste("IND",i,"b",sep="")] = ifelse(runif(length(alFrequ$SNP),0.00,1.00) < alFrequ$MAF, alFrequ$A1, alFrequ$A2)
}

我正在为“seqIndividuals”中的每个“i”创建两个新列,如果随机值低于“MAF”列,则从“A1”列检索任一值,如果高于“MAF”列,则检索“A2”。代码运行良好,但随着数据集按行和列(个人)增长,时间也显着增长。

有没有办法避免在这种情况下使用 IFELSE,因为我知道它作为一个循环工作?我尝试生成一个随机值矩阵然后替换它们,但它需要相同的时间甚至更长的时间。

mtxAlFrequ = matrix(runif(length(alFrequ$SNP)*(201)),nrow=length(alFrequ$SNP),ncol=201)
mtxAlFrequ[mtxAlFrequ < alFrequ$MAF] = alFrequ$A1

谢谢!

【问题讨论】:

  • 这两个ifelse 语句似乎在做同样的事情,除了runif 部分。如果是这种情况,您可以使用replicate(2, runif(...
  • 嗨@akrun。他们也在做同样的事情,只是创建一个具有不同名称的列,但我可以在之后更改名称。这会显着提高速度吗?谢谢
  • 试试lst &lt;- do.call(c, lapply(seqIndividuals, function(i) replicate(2, alFrequ[2:3][cbind(1:nrow(alFrequ), (runif(nrow(alFrequ), 0, 1) &gt;= alFrequ$MAF)+1)], simplify=FALSE))); nm1 &lt;- paste0("IND", rep(letters[1:2], length(seqIndividuals)), rep(seqIndividuals, each = 2)); alFrequ[nm1] &lt;- lst
  • 请试试上面的代码,看看是否提高了速度
  • Akrun,它确实更快,但并不多:510 秒与 340.000 行的 535 秒。我不希望使用超过 340K 的行,所以变化不是很显着。

标签: r for-loop matrix random dataframe


【解决方案1】:

一个选项是data.table

library(data.table)
nm1 <- paste0("IND", rep(letters[1:2], length(seqIndividuals)), 
                    rep(seqIndividuals, each = 2))
setDT(alFrequ)
for(j in seq_along(nm1)) {
      alFrequ[, nm1[j] := A2
             ][runif(.N, 0, 1) < MAF , nm1[j] := A1][]
}

基准测试

set.seed(24)
alFrequ <- data.frame(SNP= paste0('rs', sample(600000, 340000, replace=FALSE)),
                   A1 = sample(c("G", "T", "A", "C"), 340000, replace=TRUE),
                   A2 = sample(c("G", "T", "A", "C"), 340000, replace=TRUE),
                   MAF = runif(340000, 0, 1), stringsAsFactors=FALSE)
nm1 <- paste0("IND", rep(letters[1:2], length(seqIndividuals)), 
                          rep(seqIndividuals, each = 2))

system.time({
    setDT(alFrequ)
     for(j in seq_along(nm1)){
     alFrequ[, nm1[j] := A2][runif(.N, 0, 1) < MAF , nm1[j] := A1][]
   }
})
#   user  system elapsed 
#  10.72    1.05   11.76 

并在原始数据集上使用 OP 的代码

system.time({
 for(i in seqIndividuals) {
   alFrequ[paste("IND",i,"a",sep="")] = ifelse(runif(length(alFrequ$SNP),0.00,1.00) < 
          alFrequ$MAF, alFrequ$A1, alFrequ$A2)
   alFrequ[paste("IND",i,"b",sep="")] = ifelse(runif(length(alFrequ$SNP),0.00,1.00) < 
             alFrequ$MAF, alFrequ$A1, alFrequ$A2)
 }
})
#    user  system elapsed 
#   72.16    6.82   79.33 

【讨论】:

  • 490 秒,迄今为止最快。一些改进,但如果你遇到另一个想法,请告诉我:) 不过可能是不可能的。
  • @DanielFernandes 对我来说,您使用 data.table 1.10.0 和 R 3.3.2 提到的 340,000 行是 10 秒
  • 好的,我知道我有 data.table 1.9.6。让我尝试更新它。作为说明,我现在正在笔记本电脑上运行它(i7,8GB RAM)。
  • @DanielFernandes 同时,我还将运行您的代码并检查时间。我有一个 16 GB RAM i5
  • 我发现了我的问题。我的MAF 列的类型为character。我将其更改为double,就像在您的随机数据框中一样,现在它准时使用了。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 2013-10-23
  • 1970-01-01
相关资源
最近更新 更多