2

我对 Perl 代码很陌生,我正在将一些数据集与以下代码合并。数据设置如下:第一行指定样本名称,然后是第二、第三列的计数......第一列指定基因名称。我有 2 个要合并在一起的大数据集,我一直在使用以下 Perl 脚本,方法是指定 perl 脚本的路径,并在终端中运行以下代码:

$ cd /path/to/file
$ perl /path/to/file dataset1.txt dataset2.txt merged.txt

Perl 脚本如下:

use strict;
my $file1=$ARGV[0];              
my $file2=$ARGV[1];             
my $out=$ARGV[2];               
my %hash=();                     

open(RF,"$file1") or die $!;    
while(my $line=<RF>){
  chomp($line);
  my @arr=split(/\t/,$line);
  my $gene=shift(@arr);
  $hash{$gene}=join("\t",@arr);
}
close(RF);

open(RF,"$file2") or die $!;     
open(WF,">$out") or die $!;    
while(my $line=<RF>){
  chomp($line);
  my @arr=split(/\t/,$line);
  my $gene=shift(@arr);
  if(exists $hash{$gene}){
    print WF $gene . "\t" . $hash{$gene} . "\t" . join("\t",@arr) . "\n";
  }
}
close(WF);
close(RF);

使用上面的代码,我应该得到一个合并表,删除重复的行,第二个文本文件的(样本 A 到样本 Z)列合并到第一个文本文件的列(样本 1 到样本 100),所以它应该看起来像这样,由制表符分隔。

Gene Name Sample 1 Sample 2 ..... Sample A Sample B...
TP53      2.345    2.234          4.32     4.53

当我的合并文件返回合并两个数据集时出现问题,但是下一行而不是同一行中的第二个数据集。它将识别、排序和合并计数,但会进入下一行。我的代码或输入有问题吗?

感谢您的所有帮助!

4

1 回答 1

3

双行问题可能是由于输入文件中的外行结尾。您可以使用以下命令进行检查:

$ perl -MData::Dumper -ne'$Data::Dumper::Useqq=1; print Dumper $_' file1.txt

您的代码还有更多问题,如下所示。

您似乎正在做的是根据第 1 列中的名称连接行。您应该知道,这种匹配是区分大小写的,因此它将区分例如tp53and TP53、 orGene nameGene Name、或与TP53and TP53 (一个额外的空间)。这可能有好有坏,但要为极端情况做好准备。

您期望您的程序、输入文件和输出有 3 个参数,但这是一种非常不成熟的方法。我会将菱形运算符用于输入文件,然后使用 shell 命令重定向输出,例如:

$ perl foo.pl file1 file2 > merged.txt

例如,这将使您可以灵活地添加更多文件以进行合并,并为您提供在不提交文件的情况下测试合并的选项。

您正在使用 2 参数open命令,但未指定打开模式(例如"<")。这是非常危险的,并且会让您对代码注入持开放态度。例如,有人可以"| rm -rf /"作为您程序的第一个参数输入并删除您的整个硬盘驱动器(或在他们允许的范围内)。为了防止这种情况,您使用 3 参数 open 并指定硬编码的打开模式。

Perl 中的打开命令也应该使用词法文件句柄,例如my $fh,而不是全局的。它应该如下所示:

open my $fh,     "<", $input1 or die $!;
open my $fh_out, ">", $output or die $!;

但是由于我们使用的是菱形运算符,Perl 会自动为我们处理它。

您也不需要将文件的读取分成两个循环,因为您基本上是在做同样的事情。也无需先拆分线,然后将它们重新连接在一起。

我写了这个作为如何完成的示例:

use strict;
use warnings;

my %data;
while (<DATA>) {
    chomp;
    my ($name, $line) = /^([^\t]+)(.+)/;    # using a regex match avoiding split
    $data{$name} .= $line;                  # merge lines using concatenation
}

for my $name (sort keys %data) {
    print $name . $data{$name} . "\n";
}

__DATA__
Gene Name   Sample 1    Sample 2    Sample 3    Sample 4
TP53    2.345   2.234   4.32    4.53
TP54    2.345   2.234   4.32    4.53
TP55    2.345   2.234   4.32    4.53
Gene Name   Sample A    Sample B    Sample C    Sample D
TP53    2.345   2.234   4.32    2.53
TP54    2.212   1.234   3.32    6.53
TP55    1.345   2.114   7.32    5.53

在我的系统上,它给出了输出:

Gene Name      Sample 1        Sample 2        Sample 3        Sample 4        Sample A        Sample B        Sample C        Sample D
TP53    2.345   2.234   4.32    4.53    2.345   2.234   4.32    2.53
TP54    2.345   2.234   4.32    4.53    2.212   1.234   3.32    6.53
TP55    2.345   2.234   4.32    4.53    1.345   2.114   7.32    5.53

这将按字母顺序输出行。如果要保留文件的顺序,可以在读取文件时将名称收集在一个数组中,并在打印时使用它。数组保留顺序,散列键不保留。

于 2020-11-11T14:00:23.950 回答