有效地重新格式化R中的大数据集中的列条目

时间:2015-09-29 15:40:52

标签: r

我有一个大的(600万行)值表,我认为需要重新格式化才能用于与我的数据集进行比较。该表有3列我关心。 第一列含有核苷酸碱基变化,呈C> G,A> C,A> G等形式。我希望将它们分成两个独立的列。 第二列具有染色体和碱基位置,格式为10:130448,2:40483,5:30821291等。我还想将其分成两列。 第三列在许多样本群体中具有等位基因部分,格式为.02 / .03 / .20。我想将第三部分提取到一个新列中。

问题是我写的代码目前非常慢。看起来大约需要一天半才能运行。我有什么东西在这里失踪吗?任何建议,将不胜感激。

我当前的代码执行以下操作:pos,change和fraction各自接收上述值的向量split split strsplit。然后我循环遍历整个数据库,从这三个向量中获取第i个值,并使用我想要的值创建新列。

数据库格式化后,我应该可以通过染色体编号,碱基,参考等位基因,备用等位基因等轻松检查大量样本。

pos <- strsplit(total.esp$NCBI.Base, ":")
change <- strsplit(total.esp$Alleles, ">")
fraction <- strsplit(total.esp$'MAFinPercent(EA/AA/All)', "/")
for (i in 1:length(pos)){
    current <- pos[[i]]
    mutation <- change[[i]]
    af <- fraction[[i]]
    total.esp$chrom[i] <- current[1]
    total.esp$base[i] <- current [2]
    total.esp$ref[i] <- mutation[1]
    total.esp$alt[i] <- mutation[2]
    total.esp$af[i] <- af[3]

}

谢谢!

3 个答案:

答案 0 :(得分:3)

您可以使用tidyrdplyrseparate

library(tidyr)
library(dplyr)

total.esp %>% separate(Alleles, c("ref", "alt"), sep=">") %>% 
              separate(NCBI.Base, c("chrom", "base"), sep=":") %>%
              separate(MAFinPercent.EA.AA.All., c("af1", "af2", "af3"), sep="/") %>%
              select(-af1, -af2, af = af3)

你最后需要注意MAFinPercent.EA.AA.All. - 你有一个可怕的专栏名称,所以可能需要重命名/引用它取决于r的确切程度(这也是一个很好的理由)在您的问题中包含至少一些数据,例如dput(head(total.esp)))的输出。

用于检查的数据:

total.esp <- data.frame(Alleles= rep("C>G", 50), NCBI.Base = rep("10:130448", 50), 'MAFinPercent(EA/AA/All)'= rep(".02/.03/.20", 50))

因为我们现在有一个tidyr/dplyr解决方案,一个data.table解决方案和一个基本解决方案,所以我们对它们进行基准测试。首先,来自@akrun的数据,总计300,000行:

df1 <- data.frame(Alleles =rep(c('C>G', 'A>C', 'A>G'), 100000),
                  NCBI.Base=rep(c('10:130448', '2:40483', '5:30821291'),  100000),
                  MAFinPercent= rep(c('.02/.03/.20', '.05/.03/.04', '.02/.04/.03'),  100000),
                  stringsAsFactors=FALSE)

现在,基准:

microbenchmark::microbenchmark(
  tidyr = {df1 %>% separate(Alleles, c("ref", "alt"), sep=">") %>% 
                   separate(NCBI.Base, c("chrom", "base"), sep=":") %>%
                   separate(MAFinPercent, c("af1", "af2", "af3"), sep="/") %>%
                   select(-af1, -af2, af = af3)},
  data.table = {setDT(df1)[, unlist(lapply(.SD, tstrsplit,
                                           split='[>:/]', type.convert=TRUE), recursive=FALSE)]},
  base = {pos <- strsplit(df1$NCBI.Base, ":");
          change <- strsplit(df1$Alleles, ">");
          fraction <- strsplit(df1$MAFinPercent, "/");
          data.frame( chrom =sapply( pos, "[", 1), 
                      base = sapply( pos, "[", 2), 
                      ref  = sapply( change, "[", 1), 
                      alt = sapply(change, "[", 2), 
                      af  = sapply( fraction,  "[", 3)
          )}
)
Unit: seconds
       expr      min       lq     mean   median       uq      max neval
      tidyr 1.295970 1.398792 1.514862 1.470185 1.629978 1.889703   100
 data.table 2.140007 2.209656 2.315608 2.249883 2.481336 2.666345   100
       base 2.718375 3.079861 3.183766 3.154202 3.221133 3.791544   100

tidyr是赢家

答案 1 :(得分:3)

这是一个data.table解决方案。我们转换了&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df1)),使用.SD遍历Data.table(lapply)的子集,通过指定拆分字符使用tstrsplitsplit列, unlist输出recursive=FALSE

library(data.table)#v1.9.6+
setDT(df1)[, unlist(lapply(.SD, tstrsplit,
        split='[>:/]', type.convert=TRUE), recursive=FALSE)]
#   Alleles1 Alleles2 NCBI.Base1 NCBI.Base2 MAFinPercent1 MAFinPercent2
#1:        C        G         10     130448          0.02          0.03
#2:        A        C          2      40483          0.05          0.03
#3:        A        G          5   30821291          0.02          0.04
#   MAFinPercent3
#1:          0.20
#2:          0.04
#3:          0.03

注意:我假设数据集中只有3列。如果有更多列,并且只想对3列进行拆分,我们可以指定.SDcols= 1:3即列索引或实际列名,将输出分配(:=)到新列和子集仅在输出中需要的列。

数据

df1 <- data.frame(Alleles =c('C>G', 'A>C', 'A>G'), 
   NCBI.Base=c('10:130448', '2:40483', '5:30821291'), 
   MAFinPercent= c('.02/.03/.20', '.05/.03/.04', '.02/.04/.03'), 
   stringsAsFactors=FALSE)

答案 2 :(得分:2)

试试这个(保留前三行代码后):

 total.esp   <- data.frame( chrom =sapply( pos, "[", 1), 
                            base = sapply( pos, "[", 2), 
                            ref  = sapply( change, "[", 1), 
                            alt = sapply(change, "[", 2), 
                            af  = sapply( af,  "[", 3)
                           )

我无法想象这需要花费超过几分钟的时间。 (我使用类似大小的R对象。)