2

この (lowerR-10,UpperR-12) => 1 のような perl ハッシュ キーでハッシュ キーを作成したいです。ここでは、キーは (lowerR-10,UpperR-12) で、その値は 1 です。

実際、私はこのようなファイルを持っています。要素間の重なりを見つけなければなりません。

あ 10 12

あ 10 15

誰の出力が

あ 10 12 2

あ 12 15 1

最後の列は、要素間の重複を示しています。キーが (lowerR-10,UpperR-12) のようになるはずのハッシュにカウントを保存したいと思います。誰かがキーを保存する方法について何か新しい提案をすることができれば、それも素晴らしいでしょう.

ありがとう

4

3 に答える 3

0

おそらく、以下のプログラムが解決策に近づくでしょう。

#!/usr/bin/perl
use strict;
use warnings;
use Set::IntSpan;
use Sort::Naturally;

my %data;

while (<DATA>) {
    my ($chr, @start_stop) = split; 
    $data{$chr}{$_}++ for $start_stop[0] .. $start_stop[1];
}

for my $chr (nsort keys %data) {
    my %counts;
    while (my ($range_int, $count) = each %{ $data{$chr} } ) {
        push @{ $counts{$count} }, $range_int;  
    }

    for my $count (sort {$a <=> $b} keys %counts) {
        my $set = Set::IntSpan->new(@{$counts{$count}});
        for my $run ($set->sets) {
            printf "%s %-10s count: %s\n", $chr, $run, $count;
        }
    }
    print "\n";
}

__DATA__
chr1    100    500
chr1    25      50
chr1    10       50
chr1    60       80
chr1    12       40
chr1    41       45
chr1     20      45
chr1     48      80
chr1    4   60
chr2    2   40
chr3    4   90
chr1    5   40
chr2    1   30
chr1    6   20
chr4    9   100
chr1    2   20
chr2    2   90
chr1    6   20
chr4    4   30
chr2    4   90
chr3    3   90
chr2    4   90
chr4    3   90
chr2    4   30

この出力が生成されました。

chr1 2-3        count: 1
chr1 100-500    count: 1
chr1 4          count: 2
chr1 51-59      count: 2
chr1 61-80      count: 2
chr1 5          count: 3
chr1 46-47      count: 3
chr1 60         count: 3
chr1 48-50      count: 4
chr1 6-9        count: 5
chr1 21-24      count: 5
chr1 41-45      count: 5
chr1 10-11      count: 6
chr1 25-40      count: 6
chr1 12-19      count: 7
chr1 20         count: 8

chr2 1          count: 1
chr2 2-3        count: 3
chr2 41-90      count: 3
chr2 31-40      count: 4
chr2 4-30       count: 6

chr3 3          count: 1
chr3 4-90       count: 2

chr4 3          count: 1
chr4 91-100     count: 1
chr4 4-8        count: 2
chr4 31-90      count: 2
chr4 9-30       count: 3

更新:説明しようと思います。ハッシュは、%counts外側のループから染色体ごとに新たに作成されます。キーは、番号が付けられた各位置のカウントです。たとえば、番号 42 が 5 回表示されたとします。各カウントの値は、5 回表示されたすべての数値を含む無名配列です。

Set::IntSpan は、無名配列 (6、7、8、21、22、23、24、41、42、 anon配列の要素として43、44、45)。行for my $run ($set->sets)は、5 回表示された番号 (6-8、21-24、41-45) の各実行リストを取得し、それらを出力します。Set::IntSpanのドキュメントを見ることができますが、役立つ例はあまりありません。また、ネット検索で他の良い例を見つけることができませんでした。申し訳ありません。ただし、基本的には Set::IntSpan 範囲の数値を入力すると、使用する Set::IntSpan メソッドに応じて、圧縮されたサブセット (6 ~ 8、21 ~ 24 など)、またはセット内の個々の数値を取得できます。 IntSpan オブジェクトが保持するデータにアクセスします。

これでいくつかの疑問が解消されることを願っています。:-)

于 2012-10-21T19:18:46.623 に答える
0

実際、ハッシュベースのアプローチがこの問題に適しているとは思いません。リスト処理の問題としてアプローチすることをお勧めします。Haskell でのアプローチについて説明します (コードを少し追加するだけで Perl に変換できます)。

一般的なアプローチは、任意の時点で重なり合っている要素の数を集計し続けることです。これを行うには、(開始、終了) ペアとしての要素の引数リストから、「デルタ」のリスト (実行中の合計の変化) を作成します。次に、これらのデルタを発生する場所で並べ替え、同時に発生するものを結合します。最後に、デルタの実行中の合計を保持します。これは、各期間の開始時に重複する要素の数に等しくなります (各期間は次の開始時に終了します)。

完全なコード:

import Data.List      -- sortBy
import Data.Ord       -- comparing
import Data.Function  -- `on`

withDelta delta x = (x, delta)

episodeToDelta elements = increases ++ decreases
  where increases = map (withDelta 1    . fst) elements
        decreases = map (withDelta (-1) . snd) elements

compactDelta::[(Integer,Integer)]->(Integer,Integer)
compactDelta (x:xs) = ((fst x),(sum $ map snd (x:xs)))

adjustTotal (t, delta) ((t1, total1):rest) = (t, total1 + delta):(t1,total1):rest

deltasToRunningTotal = reverse . foldr adjustTotal [(0,0)] . reverse

noZeros = filter (\(_, d) -> d /= 0)

elementsToRunningTotal = deltasToRunningTotal . noZeros . map compactDelta . groupBy ((==) `on` fst) . sortBy (comparing fst) . elementToDelta

sample_elements = [(10,15),(5,9),(13,22),(15,19),(14,16),(3,8),(2,12),(20,22),(23,29)]

> sortBy (comparing fst) sample_elements
[(2,12),(3,8),(5,9),(10,15),(13,22),(14,16),(15,19),(20,22),(23,29)]

> episodesToRunningTotal sample_elements
[(0,0),(2,1),(3,2),(5,3),(8,2),(9,1),(10,2),(12,1),(13,2),(14,3),(16,2),(19,1),(20,2),(22,0),(23,1),(29,0)]
于 2012-10-22T03:43:35.203 に答える
0

ハッシュ (各染色体の %data、%counts) を表示すると、各ハッシュがどのように見えるかがよりよくわかるのではないかと考えました。ハッシュがどのように構造化されているかわからない場合は、Data::Dumper をよく使用します。とても便利なモジュールです。プログラム (以下) を実行すると、ハッシュの内容がより適切に表示されるはずです。

(私の)端末のビューが多すぎるため、おそらく出力をファイルに出力する必要があります- like: perl your_name_program.pl > junk.txt

次に、junk.txt を開いて結果を確認します。

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Sort::Naturally qw/ nsort /;

my %data;

while (<DATA>) {
    my ($chr, @start_stop) = split; 
    $data{$chr}{$_}++ for $start_stop[0] .. $start_stop[1];
}

print "Printing \%data hash as follows\n";
print Dumper \%data;
print "\n";

for my $chr (nsort keys %data) {
    my %counts;
    while (my ($range_int, $count) = each %{ $data{$chr} } ) {
        push @{ $counts{$count} }, $range_int;  
    }
    print "Printing \%counts hash for chromosome $chr\n";
    print Dumper \%counts;
    print "\n";
}

__DATA__
chr1    100    500
chr1    25      50
chr1    10       50
chr1    60       80
chr1    12       40
chr1    41       45
chr1     20      45
chr1     48      80
chr1    4   60
chr2    2   40
chr3    4   90
chr1    5   40
chr2    1   30
chr1    6   20
chr4    9   100
chr1    2   20
chr2    2   90
chr1    6   20
chr4    4   30
chr2    4   90
chr3    3   90
chr2    4   90
chr4    3   90
chr2    4   30

(この時点では、Haskell ソリューションを Perl に変換する方法についてはあまり明確ではありませんが、後で詳しく調べます。)

これにより、より明確な画像が得られることを願っています。

于 2012-10-22T16:08:05.823 に答える