2015-09-01 21 views
5

Tôi có 2 bảng (tham chiếu số &; ví dụ đồ chơi bên dưới). Các bảng này có các vị trí START và END mà tôi muốn kiểm tra các chồng chéo (sử dụng một cái gì đó như foverlaps từ gói data.table) và sau đó chia các giá trị như hiển thị bên dưới.R - Tách dòng khung dữ liệu thành hai hàng

>data <- data.table(ID=c(1,2,3), Chrom=c(1,1,2), Start=c(1,500,1000), End=c(900,5000,5000), Probes=c(899,4500,4500)) 
>Ref.table <- data.table(Chrom=c(1,2), Split=c(1000,2000)) 

>Ref.table 
Chrom Split 
1  1000 
2  2000 

>data 
ID Chrom Start End Probes 
1  1  1  900 899 
2  1  500  5000 4500 
3  2  1000  5000 4000 

Như bạn có thể thấy, ID 1 không trùng lặp với bảng tham chiếu, vì vậy nó sẽ bị bỏ lại một mình. Tuy nhiên, ID 2 & 3, tôi muốn chia dựa trên Ref.table.

Bảng kết quả tôi muốn nhận được là:

>result 
ID Chrom Start End Probes 
1  1  1  900 899 
2  1  500  1000 500 
2  1  1001  5000 4000 
3  2  1000  2000 1000 
3  2  2001  5000 3000 

Như tôi chắc chắn rằng bạn có thể thấy, có hai phần như sau: 1. chia phạm vi thành hai cột dựa trên một bảng riêng biệt 2. Phân chia # đầu dò tương ứng giữa hai phần

Tôi đã tìm kiếm gói R có thể thực hiện việc này (phạm vi phân chia bằng cánh tay nhiễm sắc thể), nhưng không thể tìm thấy điều đó như được hiển thị ở trên. Bất kỳ liên kết đến các gói chức năng sẽ được đánh giá cao, nhưng tôi cũng sẵn sàng để mã này bản thân mình ... với một chút giúp đỡ.

Cho đến nay, tôi đã chỉ có thể sử dụng foverlaps để xác định xem có sự chồng chéo: dụ:

>foverlaps(Ref.table[data[14]$Chrom], data[14], which=TRUE) 
    xid yid 
1: 1  1 

Trả lời

5

Đây là giải pháp có thể foverlaps (như đã đề cập trong câu hỏi).

Hai bước đầu tiên rất đơn giản và khá nhiều thành ngữ, thêm một End cột để Ref.table vì vậy chúng tôi sẽ có overlaping khoảng, sau đó chìa khóa cả hai bộ dữ liệu bằng cách Chrom và các cột khoảng (trong v 1.9.5+ bạn có thể hiện nay chỉ định by.xby.y thay) và chỉ cần chạy foverlaps

library(data.table) 
setDT(Ref.table)[, End := Split] 
setkey(Ref.table) 
setkey(setDT(data), Chrom, Start, End) 
res <- foverlaps(data, Ref.table) 
res 
# Chrom Split End ID Start i.End Probes 
# 1:  1 NA NA 1  1 900 899 
# 2:  1 1000 1000 2 500 5000 4500 
# 3:  2 2000 2000 3 1000 5000 4000 

Bây giờ chúng ta có sự chồng chéo, chúng ta cần phải tăng kích thước bộ dữ liệu theo các trận đấu của chúng tôi. Chúng tôi có thể điều kiện này trên is.na(Split) (có nghĩa là không tìm thấy chồng chéo).Tôi không chắc chắn nếu phần này có thể được thực hiện một cách hiệu quả hơn

res2 <- res[, if(is.na(Split)) .SD else rbind(.SD, .SD), by = .(ID, Chrom)] 
## Or, if you only have one row per group, maybe 
## res2 <- res[, if(is.na(Split)) .SD else .SD[c(1L,1L)], by = .(ID, Chrom)] 

Bây giờ, hai bước cuối cùng sẽ cập nhật các cột EndStart và sau đó cột Probes theo cột mới đánh giá cao

res2[!is.na(Split), `:=`(i.End = c(Split[1L], i.End[-1L]), 
         Start = c(Start[-1L], Split[1L] + 1L)), 
    by = .(ID, Chrom)] 
res2[!is.na(Split), Probes := i.End - Start] 
res2 
# ID Chrom Split End Start i.End Probes 
# 1: 1  1 NA NA  1 900 899 
# 2: 2  1 1000 1000 500 1000 500 
# 3: 2  1 1000 1000 1001 5000 3999 
# 4: 3  2 2000 2000 1000 2000 1000 
# 5: 3  2 2000 2000 2001 5000 2999 

(Bạn có thể xóa các cột không mong muốn nếu muốn)

+0

Điều này rất hữu ích, cảm ơn. Một trong những điều không hoạt động tốt là tỷ lệ Probesion (không chắc chắn tôi chỉ định rằng đúng trong câu hỏi anyway). Tôi đã thêm cột "Độ dài" để có độ dài ban đầu và sau đó thay vì "i.End - Start" trong câu trả lời của bạn, tôi đã làm "Đầu dò * ((i - Bắt đầu)/(Độ dài))". Trong trường hợp bất cứ ai khác đi đến câu hỏi này cho điều này, figured tôi muốn đặt nó ở đây. –

+0

@GaiusAugustus Cảm ơn bạn đã bình luận. Tôi không nhớ câu hỏi là gì nữa nhưng tôi vui vì bạn đã tìm ra nó :) –

1

Đầu tiên xác định một hàm tách:

splitter<-function(data, reftable){ 
    splitsite <- which(reftable$Chrom == data$Chrom) 
    if(reftable$Split[splitsite] > data$Start && reftable$Split[splitsite] <= data$End){ 
    return(data.frame(ID = data$ID, 
         Chrom = data$Chrom, 
         Start = c(data$Start, reftable$Split[splitsite] + 1), 
         End = c(reftable$Split[splitsite],data$End), 
         Probes = c((reftable$Split[splitsite]- data$Start)*data$Probes/(data$End-data$Start), 
           ((data$End - (reftable$Split[splitsite] + 1))*data$Probes/(data$End-data$Start))))) 
    } else { 
    return(data) 
    } 
} 

sau đó chúng ta có thể chạy trên mỗi dòng sử dụng dplyr:

library(dplyr) 
data %>% group_by(ID) %>% 
     do(splitter(., ref.table)) 

cho b elow. Bạn có thể thấy nó có 3999 và 2999 chứ không phải 4000 và 3000, tôi không chắc chắn mà bạn muốn dựa trên hàng của bạn 1. Bạn có thể sửa chữa nó bằng cách takign ra 1 trong ((data$End - (reftable$Split[splitsite] + 1))

ID Chrom Start End Probes 
1 1  1  1 900 899 
2 2  1 500 1000 500 
3 2  1 1001 5000 3999 
4 3  2 1000 2000 1000 
5 3  2 2001 5000 2999 
0

Đây là cách tiếp cận của tôi:

merge(data, Ref.table, by = "Chrom") %>% 
    mutate(
    end = ifelse(Split > Start & Split < End, Split, End), 
    start2 = ifelse(Split > Start & Split < End, end + 1, NA), 
    end2 = ifelse(Split > Start & Split < End, End, NA) 
    ) %>% 
    select(-End, -Probes, -Split) %>% 
    gather(label, value, Start, end, start2, end2, na.rm = TRUE) %>% 
    mutate(
    rep = ifelse(label %in% c("Start", "end"), 1, 2), 
    label = as.character(label), 
    label = ifelse(label %in% c("Start", "start2"), "start", label), 
    label = ifelse(label %in% c("end", "end2"), "end", label) 
    ) %>% 
    spread(label, value) %>% 
    select(ID, Chrom, start, end) %>% 
    mutate(probes = end - start) 
Các vấn đề liên quan