範囲が定義されたグループID

範囲が定義されたグループID

IDと数字(位置)を含むソートされたファイルがあります。 2番目の列の位置を500間隔のグループにグループ化する必要があります。

この行の値が前の行と比較して500未満の場合は同じグループに配置し、この行の値が500より大きい場合は別のグループに配置します。

入力ファイル:

snp00001    200
snp00002    300
snp00003    400
snp00004    500
snp00005    600
snp00006    900
snp00007    1500
snp00008    1800
snp00009    3000
snp00010    3500
snp00011    4000
snp00012    5000

希望の出力

snp00001 200 Group1
snp00002 300 Group1
snp00003 400 Group1
snp00004 500 Group1
snp00005 600 Group1
snp00006 900 Group1
snp00007 1500 Group2
snp00008 1800 Group2
snp00009 3000 Group3
snp00010 3500 Group3
snp00011 4000 Group4
snp00012 5000 Group5

追加の注意:snp00001 - snp00006は(snp00002 - snp00001)または(snp00003 - snp00002)または(snp00004 - snp00003)...の範囲が500未満であるため、同じグループ

snp00006とsnp00007は、次のグループにグループ化されています。

私はawkを試しましたが、成功しませんでした。

awk -v step=500 -v OFS='\t' '{if(NR==1 || $2+limit){group++} file="Group"group; print file,$0}' input_file

答え1

以前の値を追跡し、現在の値を保存された値と比較する必要があります。差が500を超える場合は、グループ数を増やしてください。

例えば

awk -v group=1 '{if ($2-prev>500) { group++ }} {prev=$2; $3="group" group; print}'
snp00001 200 group1
snp00002 300 group1
snp00003 400 group1
snp00004 500 group1
snp00005 600 group1
snp00006 900 group1
snp00007 1500 group2
snp00008 1800 group2
snp00009 3000 group3
snp00010 3500 group3
snp00011 4000 group3
snp00012 5000 group4

(FWIW、9/10/11出力は一貫性がありません。9 - > 10は500ですがグループを追加しませんが、10 - > 11も500ですがグループを追加します)。

答え2

使用幸せ(以前のPerl_6)

これは役に立つかもしれないわずかに異なるグループ化スキームです。 Rakuのスマートマッチ演算子を使用して、~~位置が範囲内にあるかどうかをすばやく決定します。

~$ raku -e 'my $i = 1; my $r = 1..500; for lines() {my $a = .words;  \
            if ($a.[1].Int ~~ $r) {say "$a Group", $i, " ", $r} else {  \
            repeat { $r+=500 } until ($a.[1].Int ~~ $r);  \
            say "$a Group", ++$i, " ", $r };}' file

入力例:

snp00001    200
snp00002    300
snp00003    400
snp00004    500
snp00005    600
snp00006    900
snp00007    1500
snp00008    1800
snp00009    3000
snp00010    3500
snp00011    4000
snp00012    5000

サンプル出力(ヌクレオチド1から始まり、500ヌクレオチドごとにSNPをグループ化):

snp00001 200 Group1 1..500
snp00002 300 Group1 1..500
snp00003 400 Group1 1..500
snp00004 500 Group1 1..500
snp00005 600 Group2 501..1000
snp00006 900 Group2 501..1000
snp00007 1500 Group3 1001..1500
snp00008 1800 Group4 1501..2000
snp00009 3000 Group5 2501..3000
snp00010 3500 Group6 3001..3500
snp00011 4000 Group7 3501..4000
snp00012 5000 Group8 4501..5000

上記のRakuコードは、Group#イテレータ$iと初期$r範囲を宣言します1..500。入力はとして扱われlines、各行は(スペースで区切られています)で区切られますwords。 if/else 条件の実行:if範囲、行、グループ番号、および範囲~~内の 2 番目の列 スマート一致 、範囲を取って増加し続けますが、スマート一致ではない場合は成功します。これにより、以前と同じ情報が印刷されますが、今回はGroup#が正しく増加します()。$rsayelse$rrepeat500until~~++$i

上記のグループ化方式の利点は、結果のグループがすべて同じ長さの間隔(この場合は約500ヌクレオチド)を持つことです。このスキームは、複数のSNPがわずかに一緒に配置されたときに発生する可能性があるグループ間隔の長さの「拡張」を防ぎます(間隔「拡張」は「クラスタリング」という誤った印象を生成する可能性があります)。

$mより一般的な「グループ化」ツールにするには、高速グループ化のためにRangeの右側を変数()で抽象化できます。

~$ raku -e 'my $i=1; my $m=1000; my $r = 1..$m; for lines() {my $a = .words;   if ($a.[1].Int ~~ $r) {say "$a\tGroup$i\t", $r} else { repeat { $r+=$m } until ($a.[1].Int ~~ $r); say "$a\tGroup{++$i}\t", $r };}' file
snp00001 200    Group1  1..1000
snp00002 300    Group1  1..1000
snp00003 400    Group1  1..1000
snp00004 500    Group1  1..1000
snp00005 600    Group1  1..1000
snp00006 900    Group1  1..1000
snp00007 1500   Group2  1001..2000
snp00008 1800   Group2  1001..2000
snp00009 3000   Group3  2001..3000
snp00010 3500   Group4  3001..4000
snp00011 4000   Group4  3001..4000
snp00012 5000   Group5  4001..5000

https://docs.raku.org/type/Range
https://raku.org

関連情報