2014-02-09 44 views
8

我的数据是由V6的ID分组而成的群中的每个元素的“指数”,并下令位置(V1:V3):创建用于data.table

dt 
     V1  V2  V3 V4 V5     V6 
1: chr1 3054233 3054733 . + ENSMUSG00000090025 
2: chr1 3102016 3102125 . + ENSMUSG00000064842 
3: chr1 3205901 3207317 . - ENSMUSG00000051951 
4: chr1 3206523 3207317 . - ENSMUSG00000051951 
5: chr1 3213439 3215632 . - ENSMUSG00000051951 
6: chr1 3213609 3216344 . - ENSMUSG00000051951 
7: chr1 3214482 3216968 . - ENSMUSG00000051951 
8: chr1 3421702 3421901 . - ENSMUSG00000051951 
9: chr1 3466587 3466687 . + ENSMUSG00000089699 
10: chr1 3513405 3513553 . + ENSMUSG00000089699 

我想这样做是按位置添加一个带有索引的额外列,也就是说,V6中的每个组的第一个元素是“1”,第二个元素是“2”,依此类推。我能做到这一点使用ddply和一个自定义功能:

rankExons <- function(x){ 
    if(unique(x$V5) == "+"){ 
     x$index <- seq_len(nrow(x))} 
    else{ 
     x$index <- rev(seq_len(nrow(x)))} 
    x 
} 

indexed <- ddply(dt, .(V6), rankExons) 
indexed 
    V1  V2  V3 V4 V5     V6 index 
1 chr1 3205901 3207317 . - ENSMUSG00000051951  6 
2 chr1 3206523 3207317 . - ENSMUSG00000051951  5 
3 chr1 3213439 3215632 . - ENSMUSG00000051951  4 
4 chr1 3213609 3216344 . - ENSMUSG00000051951  3 
5 chr1 3214482 3216968 . - ENSMUSG00000051951  2 
6 chr1 3421702 3421901 . - ENSMUSG00000051951  1 
7 chr1 3102016 3102125 . + ENSMUSG00000064842  1 
8 chr1 3466587 3466687 . + ENSMUSG00000089699  1 
9 chr1 3513405 3513553 . + ENSMUSG00000089699  2 
10 chr1 3054233 3054733 . + ENSMUSG00000090025  1 

不幸的是,它是完整的数据集(〜620K行)非常缓慢,当使用平行崩溃和烧伤:

library(doMC) 
registerDoMC(cores=6) 
indexed <- ddply(dt, .(V6), rankExons, .parallel=TRUE) 
Error: serialization is too large to store in a raw vector 
Error: serialization is too large to store in a raw vector 
Error: serialization is too large to store in a raw vector 
Error: serialization is too large to store in a raw vector 
Error: serialization is too large to store in a raw vector 
Error: serialization is too large to store in a raw vector 
Warning message: 
In mclapply(argsList, FUN, mc.preschedule = preschedule, mc.set.seed = set.seed, : 
    all scheduled cores encountered errors in user code 

所以,我去了data.table,但无法得到它的工作。这是我试过的:

setkey(dt, "V6") 

dt[,index:=rankExons(dt), by=V6] 
dt[,rankExons(.sd), by=V6, .SDcols=c("V5, V6")] 

而且都失败了。我如何用data.table重新创建我的ddply?

dput(dt) 
structure(list(V1 = c("chr1", "chr1", "chr1", "chr1", "chr1", 
"chr1", "chr1", "chr1", "chr1", "chr1"), V2 = c(3054233L, 3102016L, 
3205901L, 3206523L, 3213439L, 3213609L, 3214482L, 3421702L, 3466587L, 
3513405L), V3 = c(3054733L, 3102125L, 3207317L, 3207317L, 3215632L, 
3216344L, 3216968L, 3421901L, 3466687L, 3513553L), V4 = c(".", 
".", ".", ".", ".", ".", ".", ".", ".", "."), V5 = c("+", "+", 
"-", "-", "-", "-", "-", "-", "+", "+"), V6 = c("ENSMUSG00000090025", 
"ENSMUSG00000064842", "ENSMUSG00000051951", "ENSMUSG00000051951", 
"ENSMUSG00000051951", "ENSMUSG00000051951", "ENSMUSG00000051951", 
"ENSMUSG00000051951", "ENSMUSG00000089699", "ENSMUSG00000089699" 
)), .Names = c("V1", "V2", "V3", "V4", "V5", "V6"), class = c("data.table", 
"data.frame"), row.names = c(NA, -10L), .internal.selfref = <pointer: 0x1de6a88>) 
+0

+1非常很好的框架问题。 – Arun

+0

“提出好问题,获得好答案”应该是stackoverflow的座右铭:) – fridaymeetssunday

回答

14

作为一位生物信息学家,我经常遇到这种手术。这是我喜欢data.table修改行的子集引用功能!

我会做这样的:

dt[V5 == "+", index := 1:.N, by=V6] 
dt[V5 == "-", index := .N:1, by=V6] 

不需要的功能。这更有利一些,因为它避免了必须为每个组检查=="+""-"一次!相反,你可以第一子集中所有组,+一次然后按V6和修改的地方只是那些行

同样,你再次为"-"做。希望有所帮助。

注意:.N是一个特殊的变量,它包含每个组的观察次数。

+1

谢谢 - 我总是惊讶data.table速度有多快。我也和.N一起玩,但从来没有接近解决方案。 – fridaymeetssunday

3

首先,我会加载示例数据R(目前不能使用dput()data.table):

df <- read.table(header = TRUE, stringsAsFactors = FALSE, text = " 
V1  V2  V3 V4 V5     V6 
1 chr1 3205901 3207317 . - ENSMUSG00000051951 
2 chr1 3206523 3207317 . - ENSMUSG00000051951 
3 chr1 3213439 3215632 . - ENSMUSG00000051951 
4 chr1 3213609 3216344 . - ENSMUSG00000051951 
5 chr1 3214482 3216968 . - ENSMUSG00000051951 
6 chr1 3421702 3421901 . - ENSMUSG00000051951 
7 chr1 3102016 3102125 . + ENSMUSG00000064842 
8 chr1 3466587 3466687 . + ENSMUSG00000089699 
9 chr1 3513405 3513553 . + ENSMUSG00000089699 
10 chr1 3054233 3054733 . + ENSMUSG00000090025") 

你几乎可以用优雅的解决dplyr您的问题:

library(dplyr) 

df %>% 
    group_by(V6, V5) %>% 
    mutate(index = row_number(V2)) 

(我假设V2是你想索引的变量 - 我认为最好是明确的,而不是依靠行的顺序行)

但是您希望为不同的子集提供不同的摘要,这在dplyr中目前不容易。一种方法是拆分然后重新组合:

rbind_list(
    df %>% filter(V5 == "+") %>% mutate(index = row_number(V2)), 
    df %>% filter(V5 == "-") %>% mutate(index = row_number(desc(V2))) 
) 

但是这样做会相对较慢,因为您必须制作两份数据。

另一种方法是使用一个,如果汇总内:

df %>% 
    group_by(V6, V5) %>% 
    mutate(index = row_number(if (V5[1] == "+") V2 else desc(V2))) 
+0

谢谢@hadley添加dplyr解决方案。我还没有看看包装,但这可能是一个开始。 – fridaymeetssunday

+0

@fridaymeetssunday如果你熟悉plyr,转换到dplyr应该很容易。 – hadley