将一列拆分为两列

时间:2014-06-12 01:02:43

标签: r data.table

我有大data.table个基因型(260,000行乘1000列)。行是标记,列是主题。数据如下所示:

             ID1         ID2         ID3         ID4
M1:          CC          CC          TC          CC
M2:          GG          GG          GG          GG
M3:          TT          TT          TT          TT
M4:          TG          TG          TG          TG
M5:          TT          TT          TT          TT
M6:          TT          TT          TT          TT

我需要分割每个基因型,以便我在每个列中都有这样的等位基因:

             V1 V2 V3 V4 V5 V6 V7 V8
        M1:  C  C  C  C  T  C  C  C
        M2:  G  G  G  G  G  G  G  G
        M3:  T  T  T  T  T  T  T  T
        M4:  T  G  T  G  T  G  T  G
        M5:  T  T  T  T  T  T  T  T
        M6:  T  T  T  T  T  T  T  T

我提出了两个解决方案,这两个解决方案都处理数据的一个子集,但由于内存问题或我不理解的data.table内部错误导致整个数据集出现故障。

  1. 我在每列上使用strsplit并将其存储到列表中,然后使用do.call将它们全部合并。我还使用foreach函数

    对其进行了并行化
      ids <- colnames(DT)
      gene.split <- function(i) { 
      as.data.table(do.call(rbind,strsplit(as.vector(eval(parse(text=paste("DT$",ids[i])))), split = "")))
      }
      all.gene <- foreach(i=1:length(ids)) %dopar% gene.split(i)
      do.call(cbind,all.gene)
    
  2. 在4个内核上由于内存问题而中断。

    1. 第二个解决方案基于使用set函数的类似problem

       out_names <- paste("V", 1:(2*ncol(DT)), sep="_")
       invar1 <- names(DT)
      
       for (i in seq_along(invar1)) {
       set(DT, i=NULL, j=out_names[2*i-1], value=do.call(rbind, strsplit(DT[[invar1[i]]], split = ""))[,1])
       set(DT, i=NULL, j=out_names[2*i], value=do.call(rbind, strsplit(DT[[invar1[i]]], split = ""))[,2])
        }
      
    2. 适用于几列,但如果我尝试使用整个数据集,则会出现以下错误:

      集合中的错误(DT,i = NULL,j = out_names [2 * i - 1],value = do.call(rbind,:   内部逻辑错误。传递给assign的DT还没有分配足够的列槽。 l = 163,tl = 163,加1

      我是以错误的方式解决这个问题吗?

4 个答案:

答案 0 :(得分:3)

以下是使用data.table::setsubstr(非strsplit)的方法

使用@jbaums示例数据l

# coerce to `data.table` without a copy
setDT(l)
# over allocate columns so that `data.table` can assign by reference
# this will stop the error you were seeing
alloc.col(l,3000)


out_names <- paste("V", 1:(2*ncol(l)), sep="_")
invar1 <- names(l)

for (i in seq_along(invar1)) {
  set(l, i=NULL, j=out_names[2*i-1], value=substr(l[[invar1[i]]],1,1))
  set(l, i=NULL, j=out_names[2*i], value=substr(l[[invar1[i]]],2,2))
}

我的Windows 7 i7 2600机器上的最后一步需要37秒,内存为8GB

在您的示例中,您运行strsplit两次(并使用do.call(rbind....)) - &gt;没有效率。

分裂的可能方法的一些基准......

microbenchmark(substr(l[[invar1[1L]]],2,2), sapply(strsplit(l[[invar1[1L]]],''),`[`,2L),do.call(rbind, strsplit(l[[invar1[i]]], split = ""))[,2], times=5)
Unit: milliseconds
                                                      expr        min         lq     median         uq       max neval
                             substr(l[[invar1[1L]]], 2, 2)   14.10669   14.35571   14.57485   15.78283  193.9125     5
            sapply(strsplit(l[[invar1[1L]]], ""), `[`, 2L)  345.92969 1420.03907 1944.33873 3864.82876 5371.6130     5
 do.call(rbind, strsplit(l[[invar1[i]]], split = ""))[, 2] 3318.70878 4131.38551 4155.06126 5269.92745 8414.4948     5

答案 1 :(得分:2)

这是一个相对快速的方法 - 花了大约80秒(在创建虚拟数据之后)(Win 8.1 x64; i4770)但是咀嚼了大约13 GB的RAM。

# Creating initial data 
pairs <- c(outer(c('C', 'T', 'G', 'A'), c('C', 'T', 'G', 'A'), 'paste0'))
l <- replicate(1000, sample(pairs, 260000, replace=TRUE), simplify=FALSE)

system.time({
  v <- do.call(paste0, l)
  rm(l); gc()
  out <- do.call(rbind, strsplit(v, ''))
  rm(v); gc()
})

#   user  system elapsed 
#  79.07    1.24   80.33 

str(out)

# chr [1:260000, 1:2000] "A" "C" "C" "C" ...

答案 2 :(得分:0)

以下是对数据框x

执行此操作的方法
do.call(cbind, 
        lapply(x, 
               function(i) do.call(rbind, strsplit(as.character(i), split=''))
        )
)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] "C"  "C"  "C"  "C"  "T"  "C"  "C"  "C" 
[2,] "G"  "G"  "G"  "G"  "G"  "G"  "G"  "G" 
[3,] "T"  "T"  "T"  "T"  "T"  "T"  "T"  "T" 
[4,] "T"  "G"  "T"  "G"  "T"  "G"  "T"  "G" 
[5,] "T"  "T"  "T"  "T"  "T"  "T"  "T"  "T" 
[6,] "T"  "T"  "T"  "T"  "T"  "T"  "T"  "T" 

每列被拆分为字符,然后r绑定在一起。这会给出一个列列表,然后传递给cbind

答案 3 :(得分:-1)

## make a small data.table for testing
dd <- data.table(ID1=c("CC","TG"),ID2=c("CC","TG"), ID3=c("TC","TG"))
dd
##    ID1 ID2 ID3
## 1:  CC  CC  TC
## 2:  TG  TG  TG

## the first base
apply(dd,1:2,function(e) strsplit(e,split='')[[1]][1])
##      ID1 ID2 ID3
## [1,] "C" "C" "T"
## [2,] "T" "T" "T"

## the second base
apply(dd,1:2,function(e) strsplit(e,split='')[[1]][2])
##      ID1 ID2 ID3
## [1,] "C" "C" "C"
## [2,] "G" "G" "G"

## These results are in matrix, if you need data.table use as.data.table to convert them back.