2016-04-14 12 views
1

私はゲノム範囲のdata.frame(染色体と開始位置)から始めています。私は、1)隣り合っている行と2)他の2つの列の値を共有する行を結合しようとしています。注:私は実際のデータが1000万行以上あるので効率的な方法が欲しいです。R - data.frameの行を比較する(条件に基づいて結合する)

(可能であればdata.table)玩具データ:これらは隣接しているので、1 & 2を組み合わせることができる

DF <- data.frame(SampleID = c(1,1,1,1,1,2,2), 
       Chr = c(1,1,1,1,2,1,1), 
       Start = c(1, 101, 201, 401, 500, 1, 101), 
       End = c(100, 200, 300, 499, 599, 100, 200), 
       State = c(3,3,2,3,3,2,2) 
       ) 
DF 
    SampleID Chr Start End State 
1:  1 1  1 100  3 
2:  1 1 101 200  3 
3:  1 1 201 300  2 
4:  1 1 401 499  3 
5:  1 2 500 501  3 
6:  2 1  1 100  2 
7:  2 1 101 200  2 

ライン(1-100 & 101-200)およびSampleID(1)及びStateを共有(3)。

以下を組み合わせることができない。

  • 線2 & 3はState S
  • 線3 & 4にミスマッチしているが隣接していないとState
  • 線4 & 5を共有しない(染色体中の異なりますChr
  • ライン6 & 7は異なるSampleIDです。

等が挙げられる。これらをすべて適用すると、最終的な表が作成されます。

FinalDF <- data.frame(SampleID = c(1,1,1,1,2), 
         Chr = c(1,1,1,2,1), 
         Start = c(1,201,401,500,1), 
         End = c(200,300,499,599,200), 
         State = c(3,2,3,3,2)) 
FinalDF 
    SampleID Chr Start End State 
1  1 1  1 200  3 
2  1 1 201 300  2 
3  1 1 401 499  3 
4  1 2 500 599  3 
5  2 1  1 200  2 

これまでのところ、私はGenomicRangesパッケージのreduce関数を使用しようとしましたが、動作しません。

誤った出力

reduce(DF2) 
GRanges object with 3 ranges and 0 metadata columns: 
     seqnames  ranges strand 
     <Rle> <IRanges> <Rle> 
    [1]  1 [ 1, 300]  * 
    [2]  1 [401, 499]  * 
    [3]  2 [500, 501]  * 
    ------- 
    seqinfo: 2 sequences from an unspecified genome; no seqlengths 

私data.frames 10万行の長以上ですが、それを把握することができていないので、私は、data.tableで何かをしようとしていました。

次の質問は、同じ行にあります(もう少し複雑です)が、解決策はありません。 R- collapse rows based on contents of two columns

答えて

4
library(data.table) 

dt = as.data.table(DF) # or convert in place using setDT 

dt[, .(Start = min(Start), End = max(End), State = State[1]) 
    , by = .(SampleID, Chr, rleid(State), 
      cumsum(c(FALSE, head(End + 1, -1) < tail(Start, -1))))] 
# SampleID Chr rleid cumsum Start End State 
#1:  1 1  1  0  1 200  3 
#2:  1 1  2  0 201 300  2 
#3:  1 1  3  1 401 499  3 
#4:  1 2  3  1 500 599  3 
#5:  2 1  4  1  1 200  2 
+0

これは素晴らしい、非常に速く(0.51秒で動作します(DF、SampleID、Chr、状態、info1、info2、info3) 、私はdata.tableが大好きです)。ただし、保存したい列の情報が失われてしまいます。私はby文にそれらを追加できると仮定します(これは0.61秒に時間を変更します)。これはこれを処理する最善の方法ですか? –

+1

それらをグループ化している場合は、「はい」に追加します。もしそれらをグループ化していないのですが、既存のグループと同じであれば、上記の 'State [1]'に似た最初の要素を追加することができます – eddi

2

私はあなたが何をしたいのかを正しく解釈するならば、私は次のことをお勧め:あなたがに実行する場合、(各グループ内の範囲を把握するためにGenomicRangesを使用し、あなたが独立しておきたいメタデータによってグループにdplyrを使用し、パフォーマンス面ではGenomicRangesにはdata.frameが必要で、それを手で実装すると、dyplrとdata.tablesのパフォーマンスを活用することができます。ここでは(それが簡単に起こっているのかを見るために作るためにパイプ%>%を利用して)これが機能する方法の例です:

DF <- data.frame(SampleID = c(1,1,1,1,1,2,2), 
       Chr = c(1,1,1,1,2,1,1), 
       Start = c(1, 101, 201, 401, 500, 1, 101), 
       End = c(100, 200, 300, 499, 599, 100, 200), 
       State = c(3,3,2,3,3,2,2) 
) 

library(dplyr) 
# take your data frame 
DF %>% 
    # group it by the subsets 
    group_by(SampleID, Chr, State) %>% 
    # operate on each group 
    do(
    # turn subset into a GRanges object 
    as(as.data.frame(.), "GRanges") %>% 
     # reducae ranges 
     GenomicRanges::reduce() %>% 
     # turn back into data frame for dplyr to stitch together 
     as.data.frame() %>% 
     # get the information you want 
     select(start, end, width) 
) %>% 
    # ungroup for future operations 
    ungroup() %>% 
    # sort by what makes most sense for your set 
    arrange(SampleID, Chr, start) 

は出力:

Source: local data frame [5 x 6] 

SampleID Chr State start end width 
(dbl) (dbl) (dbl) (int) (int) (int) 
1  1  3  1 200 200 
1  1  2 201 300 100 
1  1  3 401 499 99 
1  2  3 500 599 100 
2  1  2  1 200 200 
+0

これは素晴らしい作品(データフレームとGRangesオブジェクトの間の転送のような)情報を失うことを除けば、私は保存したい追加の列を持っています。私はそれらをgroup()ステートメントに加えることができると仮定しますが、それはかなり減速しているようです(自分のコードを使って私のデータで63秒、グループステートメントに追加してから413秒)。何か提案はありますか? –

+0

追加の列に含まれる内容によって異なります。これがトリプレット(sampleId、Chr、State)の各組み合わせに常に同じ値を持つ追加情報であれば、最後にmerge(または、 'dplyr'の中のleft_join)を使用して、元に戻します。各(sampleId、Chr、State)サブセット内で変数値を持つことができる場合は、グループに含める必要があります。そうでなければ、どちらが正しい値を使用するかをどのように知っていますか? (行が崩壊したため)。 – sebkopf

+1

ps:前者の場合は、コードの最後に(別の '%>% 'を付けて)これを行う方法です:' arrange(SampleID、Chr、start)%>% left_join( distinct ( "SampleID"、 "Chr"、 "State") で ) ' – sebkopf

1
# This code is kind of robust but it appears to get the job done 

DF <- data.frame(SampleID = c(1,1,1,1,1,2,2), 
       Chr = c(1,1,1,1,2,1,1), 
       Start = c(1, 101, 201, 401, 500, 1, 101), 
       End = c(100, 200, 300, 499, 599, 100, 200), 
       State = c(3,3,2,3,3,2,2) 
) 

test_and_combine <- function(r1,r2) { 
    if (r1[,1] == r2[,1] & # check if "SampleID" column matches 
     r1[,2] == r2[,2] & # check if "Chr" column matches 
     (r1[,4] + 1) == r2[,3] & # test if Start and End are in sequence 
     r1[,5] == r2[,5]) # check if "State"column matches 
    { 
    # merge rows if true 
    DF_comb <- r1[,] 
    DF_comb[1,4] <- r2[,4] 

    } 
    else{ 
    DF_comb <- NA 
    } 
    return(DF_comb) 
} 

# This section could rewritten to use Reduce() 
DF_comb_final <- data.frame() 
for(i in 1:(nrow(DF)-1)){ # loop through ever row of data.frame 
    DF_temp <- test_and_combine(DF[i,],DF[i+1,]) # send two rows to function 
    if(!any(is.na(DF_temp))){ 
    DF_comb_final <- rbind(DF_comb_final,DF_temp)  
    } 
} 
関連する問題