2

私は2つのファイルを持っています:

  • file_1には、3つの列(Marker(SNP)、Chromosome、およびposition)があります。
  • file_2には、3つの列(Chromosome、peak_start、およびpeak_end)があります。

SNP列を除くすべての列は数値です。

ファイルはスクリーンショットに示されているように配置されています。file_1には行として数百のSNPがあり、file_2には61のピークがあります。各ピークは、peak_startとpeak_endでマークされます。どちらのファイルにも23の染色体のいずれかが存在する可能性があり、file_2には染色体ごとにいくつかのピークがあります。

file_1のSNPの位置が、一致する各染色体のfile_2のpeak_startとpeak_endの範囲内にあるかどうかを調べたいと思います。もしそうなら、どのSNPがどのピークにあるかを示したい(できればタブ区切りファイルに出力を書き込む)。

ファイルを分割し、染色体がキーとなるハッシュを使用したいと思います。これに似た質問をいくつか見つけましたが、提案された解決策をよく理解できませんでした。

これが私のコードの例です。これは私の質問を説明するためだけのものであり、これまでのところ何もしていないので、「擬似コード」と考えてください。

#!usr/bin/perl

use strict;
use warnings;

my (%peaks, %X81_05);
my @array;

# Open file or die

unless (open (FIRST_SAMPLE, "X81_05.txt")) {
    die "Could not open X81_05.txt";
}

# Split the tab-delimited file into respective fields

while (<FIRST_SAMPLE>) {

    chomp $_;
    next if (m/Chromosome/); # Skip the header

    @array = split("\t", $_);
    ($chr1, $pos, $sample) = @array;

    $X81_05{'$array[0]'} = (
        'position' =>'$array[1]'
    )
}

close (FIRST_SAMPLE);

# Open file using file handle
unless (open (PEAKS, "peaks.txt")) {
    die "could not open peaks.txt";
}

my ($chr, $peak_start, $peak_end);

while (<PEAKS>) {
    chomp $_;

    next  if (m/Chromosome/); # Skip header
    ($chr, $peak_start, $peak_end) = split(/\t/);
    $peaks{$chr}{'peak_start'} = $peak_start;
    $peaks{$chr}{'peak_end'}  = $peak_end;
}

close (PEAKS);

for my $chr1 (keys %X81_05) {
    my $val = $X81_05{$chr1}{'position'};

    for my $chr (keys %peaks) {
        my $min = $peaks{$chr}{'peak_start'};

        my $max = $peaks{$chr}{'peak_end'};

        if (($val > $min) and ($val < $max)) {
            #print $val, " ", "lies between"," ", $min, " ", "and", " ", $max, "\n";
        }
        else {
                #print $val, " ", "does not lie between"," ", $min, " ", "and", " ", $max, "\n";
        }
    }
}

より素晴らしいコード:

  1. http://i.stack.imgur.com/fzwRQ.png
  2. http://i.stack.imgur.com/2ryyI.png
4

4 に答える 4

3

Perl でのプログラムのヒント:

あなたはこれを行うことができます:

open (PEAKS, "peaks.txt") 
   or die "Couldn't open peaks.txt";

これの代わりに:

unless (open (PEAKS, "peaks.txt")) {
    die "could not open peaks.txt";
}

これはより標準的な Perl であり、読みやすくなっています。

標準 Perl について言えば、引数が 3 つのオープン形式を使用し、ファイル ハンドルにスカラーを使用する必要があります。

open (my $peaks_fh, "<", "peaks.txt") 
   or die "Couldn't open peaks.txt";

|このように、ファイルの名前がたまたままたはで始まる場合>でも、それは機能します。スカラー変数 (a で始まる変数$) を使用すると、関数間でファイル ハンドルを簡単に渡すことができます。

とにかく、私があなたを正しく理解していることを確認するために: あなたは「私は... 染色体が鍵であるハッシュを使用したい」と言いました。

現在、私は 23 対の染色体を持っていますが、これらの染色体のそれぞれには数千の SNP が含まれている可能性があります。このように染色体ごとにキーを設定すると、染色体ごとに 1 つの SNP しか保存できません。これは、あなたの望むことですか?あなたのデータがすべて同じ染色体を示していることに気付きました。つまり、染色体でキーを設定することはできません。私は今のところそれを無視し、私自身のデータを使用しています。

ファイルに含まれているとあなたが言った内容と、プログラムがそれらをどのように使用するかにも違いがあることに気付きました。

「ファイル 1 には 3 つの列 (SNP、染色体、および位置) があります」と言いましたが、コードは次のとおりです。

($chr1, $pos, $sample) = @array;

私が想定しているのは、染色体、位置、および SNP です。ファイルはどのように配置されていますか?

何を求めているのかを正確に明確にする必要があります。

とにかく、これはタブ区切り形式で印刷されるテスト済みのバージョンです。これは、もう少し現代的な Perl 形式です。(指定したように)染色体ごとのハッシュが1つしかないことに注意してください。最初に読んだpeaks.txt。自分の位置ファイルに存在しない染色体を見つけた場合、peaks.txt単純にそれを無視します。それ以外の場合は、 POSITIONおよびSNPの追加のハッシュを追加します。

指定したとおりにすべて (タブ区切り) を出力する最終ループを実行しますが、形式を指定しませんでした。必要に応じて変更してください。

#! /usr/bin/env perl

use strict;
use warnings;
use feature qw(say);
use autodie;        #No need to check for file open failure
use constant {
    PEAKS_FILE        => "peak.txt",
    POSITION_FILE => "X81_05.txt",
};

open ( my $peak_fh, "<", PEAKS_FILE );
my %chromosome_hash;

while ( my $line = <$peak_fh> ) {
    chomp $line;
    next if $line =~ /Chromosome/;   #Skip Header
    my ( $chromosome, $peak_start, $peak_end ) = split ( "\t", $line );
    $chromosome_hash{$chromosome}->{PEAK_START} = $peak_start;
    $chromosome_hash{$chromosome}->{PEAK_END} = $peak_end;
}
close $peak_fh;

open ( my $position_fh, "<", POSITION_FILE );

while ( my $line = <$position_fh> ) {
    chomp $line;
    my ( $chromosome, $position, $snp ) = split ( "\t", $line );
    next unless exists $chromosome_hash{$chromosome};

    if ( $position >= $chromosome_hash{$chromosome}->{PEAK_START}
            and $position <= $chromosome_hash{$chromosome}->{PEAK_END} ) {
        $chromosome_hash{$chromosome}->{SNP} = $snp;
        $chromosome_hash{$chromosome}->{POSITION} = $position;
    }
}
close $position_fh;

#
# Now Print
#

say join ("\t", qw(Chromosome, SNP, POSITION, PEAK-START, PEAK-END) );
foreach my $chromosome ( sort keys %chromosome_hash ) {
    next unless exists $chromosome_hash{$chromosome}->{SNP};
    say join ("\t",
        $chromosome,
        $chromosome_hash{$chromosome}->{SNP},
        $chromosome_hash{$chromosome}->{POSITION},
        $chromosome_hash{$chromosome}->{PEAK_START},
        $chromosome_hash{$chromosome}->{PEAK_END},
    );
}

いくつかのこと:

  • 両側の括弧の周りにスペースを残してください。読みやすくなります。
  • 他の人が使用しない場合、私は括弧を使用します。現在のスタイルは、必要がない限り使用しないことです。私は、複数の引数を取るすべての関数にそれらを使用する傾向があります。たとえば、 と言うこともできopen my $peak_fh, "<", PEAKS_FILE;ましたが、関数に 3 つのパラメーターがあると、パラメーターが失われ始めると思います。
  • 使用することに注意してくださいuse autodie;。これにより、ファイルを開くことができない場合、プログラムが終了します。そのため、ファイルが開かれたかどうかをテストする必要さえありません。
  • ハッシュのハッシュの構造を隠すには、オブジェクト指向の Perl を使用することをお勧めします。START_PEEKこれにより、開始ピークがではなくに格納されていると考えるなどのエラーが防止されPEAK_STARTます。Perl は、これらのタイプのミスキー エラーを検出しません。したがって、配列の配列またはハッシュのハッシュを行うときは常にオブジェクトを使用することを好みます。
于 2012-05-14T03:56:39.943 に答える
1

for2 番目のロットでいくつかの SNP が見つかると予想されるため、必要なループは 1 つだけです。したがって、%X81_05ハッシュをループして、一致するものがあるかどうかを確認します%peak。何かのようなもの:

for my $chr1 (keys %X81_05)
{
    if (defined $peaks{$chr1})
    {
        if (    $X81_05{$chr1}{'position'} > $peaks{$chr1}{'peak_start'}
             && $X81_05{$chr1}{'position'} < $peaks{$chr1}{'peak_end'})
        {
            print YOUROUTPUTFILEHANDLE $chr1 . "\t"
              . $peaks{$chr1}{'peak_start'} . "\t"
              . $peaks{$chr1}{'peak_end'};
        }
        else
        {
            print YOUROUTPUTFILEHANDLE $chr1
              . "\tDoes not fall between "
              . $peaks{$chr1}{'peak_start'} . " and "
              . $peaks{$chr1}{'peak_end'};
        }
    }
}

注: コードはテストしていません。

追加したスクリーンショットを見ると、これは機能しません。

于 2012-05-13T23:27:54.140 に答える
0

@Davidによって提起されたポイントは良いです。それらをプログラムに組み込むようにしてください。(@David の投稿からほとんどのコードを借用しました。)

私が理解できなかったことの 1 つは、ピーク値とハッシュの位置の両方をロードする理由です。各染色体には複数のレコードがあるため、HoA を使用します。私の解決策はそれに基づいています。列とその位置を変更する必要がある場合があります。

use strict;
use warnings;

our $Sep = "\t";
open (my $peak_fh, "<", "data/file2");
my %chromosome_hash;

while (my $line = <$peak_fh>) {
    chomp $line;
    next if $line =~ /Chromosome/; #Skip Header
    my ($chromosome) = (split($Sep, $line))[0];
    push @{$chromosome_hash{$chromosome}}, $line; # Store the line(s) indexed by chromo
}
close $peak_fh;

open (my $position_fh, "<", "data/file1");

while (my $line = <$position_fh>) {
    chomp $line;
    my ($chromosome, $snp, $position) = split ($Sep, $line);
    next unless exists $chromosome_hash{$chromosome};

    foreach my $peak_line (@{$chromosome_hash{$chromosome}}) {
        my ($start,$end) = (split($Sep, $line))[1,2];

        if ($position >= $start and $position <= $end) {
            print "MATCH REQUIRED-DETAILS...$line-$peak_line\n";
        }
        else {
            print "NO MATCH REQUIRED-DETAILS...$line-$peak_line\n";
        }
    }
}
close $position_fh;
于 2012-05-14T07:33:02.233 に答える
0

この問題を解決するために、@tuxuday と @David のコードを使用しました。これが私が望んでいた最終的なコードです。多くのことを学んだだけでなく、問題をうまく解決することができました! 称賛の皆さん!

use strict;
use warnings;
use feature qw(say);

# Read in peaks and sample files from command line
my $usage = "Usage: $0 <peaks_file> <sample_file>";
my $peaks = shift @ARGV or die "$usage \n";
my $sample = shift @ARGV or die "$usage \n";

our $Sep = "\t";
open (my $peak_fh, "<", "$peaks");
my %chromosome_hash;

while (my $line = <$peak_fh>) {
    chomp $line;
    next if $line =~ /Chromosome/; #Skip Header
    my ($chromosome) = (split($Sep, $line))[0];

    push @{$chromosome_hash{$chromosome}}, $line; # Store the line(s) indexed by chromosome
}
close $peak_fh;

open (my $position_fh, "<", "$sample");

while (my $line = <$position_fh>) {
    chomp $line;
    next if $line =~ /Marker/; #Skip Header
    my ($snp, $chromosome, $position) = split ($Sep, $line);

    # Check if chromosome in peaks_file matches chromosome in sample_file
    next unless exists $chromosome_hash{$chromosome};

    foreach my $peak_line (@{$chromosome_hash{$chromosome}}) {

        my ($start,$end,$peak_no) = (split( $Sep, $peak_line ))[1,2,3];

        if ( $position >= $start and $position <= $end) {

            # Print output
            say join ("\t",
                $snp,
                $chromosome,
                $position,
                $start,
                $end,
                $peak_no,
            );
        }
        else {
            next; # Go to next chromosome
        }
    }
}
close $position_fh;
于 2012-05-15T16:33:12.953 に答える