【问题标题】:print hashes with values from different files使用来自不同文件的值打印散列
【发布时间】:2017-04-19 04:11:41
【问题描述】:

我想创建具有来自文件 1 和文件 2 的值的输出文件。

文件 1 中的行:

chr1 袖扣外显子 708356 708487 1000 - .
基因ID“CUFF.3”;成绩单ID“CUFF.3.1”;外显子编号“5”; FPKM “3.1300591420”; frac "1.000000"; conf_lo "2.502470"; conf_hi “3.757648”;科夫“7.589085”; chr1袖扣外显子 708356 708487 。 - 。基因ID“XLOC_001284”;成绩单_id “TCNS_00007667”;外显子编号“7”;基因名称“LOC100288069”; oId “袖带.15.2”;最近的_ref "NR_033908";类代码“j”; tss_id "TSS2981";

文件 2 中的行:

袖带.48557
chr4:160253850-160259462:160259621-160260265:160260507-160262715

此文件的第二列是唯一 id (uniq_id)。

我想得到以下格式的输出文件: transcript_id(CUFF_id) uniq_id gene_id(XLOC_ID) FPKM

我的脚本从第一个文件中获取 XLOC_ID 和 FPKM 值,并将它们与第二个文件中的两列一起打印。

#!/usr/bin/perl -w

use strict;

my $v_merge_gtf = shift @ARGV or die $!;
my $unique_gtf = shift @ARGV or die $!;

my %fpkm_hash;
my %xloc_hash;

open (FILE, "$v_merge_gtf") or die $!;
while (<FILE>) {
    my $line = $_;
    chomp $line;
    if ($line =~ /[a-z]/) {
        my @array = split("\t", $line);
        if ($array[2] eq 'exon') {
            my $id = $array[8];
            if ($id =~ /transcript_id \"(CUFF\S+)/) {
                $id = $1;
                $id =~ s/\"//g;
                $id =~ s/;//;
            }

            my $fpkm = $array[8];
            if ($fpkm =~ /FPKM \"(\S+)/) {
                $fpkm = $1;
                $fpkm =~ s/\"//g;
                $fpkm =~ s/;//;
            }

            my $xloc = $array[17];
            if ($xloc =~ /gene_id \"(XLOC\S+)/) {
                $xloc = $1;
                $xloc =~ s/\"//g;
                $xloc =~ s/;//;
            }
            $fpkm_hash{$id} = $fpkm;
            $xloc_hash{$id} = $xloc;
        }
    }
}

close FILE;


open (FILE, "$unique_gtf") or die $!;
while (<FILE>) {
    my $line = $_;
    chomp $line;
    if ($line =~ /[a-z]/) {
        my @array = split("\t", $line);
        my $id = $array[0];
        my $uniq = $array[1];
        print $id . "\t" . $uniq . "\t" . $xloc_hash{$id} . "\t" . $fpkm_hash{$id} . "\n";
    }
}

close FILE;

我在文件之外初始化了哈希值,但是对于每个 CUFF 值,我得到以下错误:

袖带.24093
chr17:3533641-3539345:3527526-3533498:3526786-3527341:3524707-3526632

在连接 (.) 或 ex_1.pl 处的字符串中使用未初始化的值 第 55 行,第 9343 行。

在连接 (.) 或 ex_1.pl 处的字符串中使用未初始化的值 第 55 行,第 9343 行。

我该如何解决这个问题?

谢谢!

【问题讨论】:

  • 我为您的困惑道歉。错误是指带有 print 语句的行: print $id 。 "\t" 。 $uniq 。 "\t" 。 $xloc_hash{$id} 。 "\t" 。 $fpkm_hash{$id} 。 "\n";
  • 嗯,其中一个值未初始化。哪一个?可能你输入的数据不一致。

标签: perl hash printing


【解决方案1】:

我认为警告消息是因为 $id 键 (CUFF.24093),您在第二个文件的行 9343 中不包含您在第一个文件中创建的哈希值。

是否有可能第二个文件中的 ID 不包含在第一个文件中?这里似乎是这样。

如果是这样,并且您只想跳过这个未知 ID,您可以在您的程序中添加一行,例如:

my $id = $array[0];
my $uniq = $array[1];

next unless exists $fpkm_hash{$id}; # add this line

print $id . "\t" . $uniq . "\t" . $xloc_hash{$id} . "\t" . $fpkm_hash{$id} . "\n";

这将绕过下面的print 语句并返回到while 循环的顶部并读入下一行并继续处理。

这取决于您遇到未知 ID 时要采取的措施。

更新:我想我可能会对您的代码进行一些观察/改进。

my $v_merge_gtf = shift @ARGV or die $!;
my $unique_gtf = shift @ARGV or die $!;

错误变量$! 在这里没有用处(这是我最近才发现的事实,即使是在使用 Perl 14 年后)。 $! 仅用于系统调用(涉及操作系统)。最常见的是 open 和 close 用于文件,opendir 和 closedir 用于目录。如果在打开/关闭文件或目录时发生错误,$! 将包含错误消息。 (在我包含的代码中查看我是如何处理这个问题的 - 我创建了一条消息,$usage,如果 shift 没有成功,则打印出来。

我没有使用 2 个哈希值来存储信息,而是使用了 1 个哈希值%data。优点是它会使用更少的内存(因为它只存储 1 组键而不是 2 组),不过,如果您愿意,也可以使用 2 组。

我使用推荐的 3 参数 (filehandle, mode, filename) 形式打开文件。您使用的 2 参数方法已过时且不太安全(出于此处不详述的原因)。此外,我使用的词法文件句柄my $mrgmy $unique 是创建文件句柄的新方法(而不是使用FILE 进行两次打开)。

您可以像while (my $line = &lt;FILE&gt;) 一样在您的while 循环中直接分配给$line,而不是按照您的方式分配。在我的示例程序中,我没有分配给$line,而是依赖于默认变量$_。 (它简化了以下两个语句,next unless /\S/; my @array = split /\t/;)。对于第一个文件,我没有 chomp,因为您只在字符串内部进行解析,并且没有使用字符串末尾的任何内容。chomp 对于第二个 while 循环是必需的,因为第二个变量 @如果 chomp 没有将其删除,则 987654348@ 的末尾会有一个换行符。

我不知道你的这句话是什么意思,if ($line =~ /[a-z]/)。我假设您想检查空行并且只处理具有非空间数据的行。这就是我写next unless /\S/;的原因。 (说跳过以下语句并到达 while 循环的顶部并读取下一条记录)。

您的第一个 while 循环有效,因为您的输入文件中没有错误。如果有错误,那么您编写代码的方式可能有问题。

语句my $id = $array[8];$id 提供了一个值,如果以下if 语句为假,则该值将被错误使用。 (对于您要捕获的其他 2 个变量,$fpkm$xloc 也是如此)。您可以在我的代码示例中看到我是如何处理这个问题的。

在我的代码中,如果匹配不成功,我就死了,你可能不想die,而是说match or next 来尝试下一行数据。这取决于您希望如何处理失败的匹配。

在这一行$array[8] =~ /gene_id "(CUFF\S+)";/,注意我把";放在捕获的数据后面,所以不需要从捕获的数据中删除它(就像你在替换中所做的那样)

好吧,我知道这是对您的代码的长评论,但我希望您对我为什么推荐给定的更改有一些好的想法。

or die "Could not find ID in $v_merge_gtf (line# $.)";

$. 是正在读取的文件的行号。

#!/usr/bin/perl
use warnings;
use strict;

my $usage = "USAGE: perl $0 merge_gtf_file unique_gtf_file\n";

my $v_merge_gtf = shift @ARGV or die $usage;
my $unique_gtf = shift @ARGV or die $usage;

my %data;

open my $mrg, '<', $v_merge_gtf or die $!;

while (<$mrg>) {
    next unless /\S/;
    my @array = split /\t/;
    if ($array[2] eq 'exon') {

        $array[8] =~ /gene_id "(CUFF\S+)";/
            or die "Could not find ID in $v_merge_gtf (line# $.)";
        my $id = $1;

        $array[8] =~ /FPKM "(\S+)";/
            or die "Could not find FPKM in $v_merge_gtf (line# $.)";
        my $fpkm = $1;

        $array[17] =~ /gene_id "(XLOC\S+)";/
            or die "Could not find XLOC in $v_merge_gtf (line# $.)";
        my $xloc = $1;

        $data{$id}{fpkm} = $fpkm;
        $data{$id}{xloc} = $xloc;
    }
}
close $mrg or die $!;


open my $unique, '<', $unique_gtf or die $!;
while (<$unique>) {
    next unless /\S/;
    chomp;
    my ($id, $uniq) = split /\t/;
    print join("\t", $id, $uniq, $data{$id}{fpkm}, $data{$id}{xloc}), "\n";
}

close $unique or die $!;

【讨论】:

  • 非常感谢您的宝贵建议。我用 $id 修改了行,而不是 transcript_id 我使用了gene_id。从那时起,哈希中的 $id 和数组中的 $id 开始保持一致,我修复了错误。
  • @Olha Kholod 我已经在我的帖子中添加了一个包含大量信息的更新
  • 感谢您逐行解释代码。我非常感谢您的时间和工作,并同意您的大部分陈述。我是编程新手,所以我的一些行可能不像你在更新中建议的那样复杂。将来我会努力提高自己的技能以克服这些问题。
猜你喜欢
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 2017-08-22
  • 2013-08-10
  • 1970-01-01
  • 2023-02-01
  • 2013-02-19
相关资源
最近更新 更多