【问题标题】:matching values (multiple if-functions) between two files and pasting the values在两个文件之间匹配值(多个 if 函数)并粘贴值
【发布时间】:2013-08-23 15:38:07
【问题描述】:

我有两个包含多个列的 txt 文件。这是第一个文件 ($frequency) 的样子:

C1    C2    A  a   B   b   C   c   D   d
text   1    0  1   0   0   0   0   0   0
text   2    1  0   5   4   0   0   0   0
text   3    0  0   0   0   10  11  3   6
text   4    1  0   9   4   0   2   0   0
text   5    5  3   0   0   6   7   4   0

所以 C2 包含从 1 到 20000 的所有位置。A-d 列包含所有等于或大于 0 的数值。

这是第二个文件 ($variants) 的样子

C1    C2    C3   C4  
text   2    A    D  
text   4    B    C 
text   5    A    B,D

这里的 C2 包含 1 到 20000 之间的一些值。C3 和 C4 包含 A-D 之间的字母(如表 1 中的列名,但都是大写字母)。我现在要做的是:将$variants中的C2中的值与$frequency中的C2中的值匹配,然后检查$variants的C3中的哪个字母,然后复制相应的值(所以正确的行并更正带有大写和小写字母的列)从$frequency 到$variants 中的两个新列。然后需要对 $variants 的 C4 执行相同操作。

编辑:有时$variants 中的 C4 也可能包含两个由“,”分隔的字母。对于这两个字母,来自$frequency 的值应该出现在输出中

根据这个例子,输出应该是这样的

C1    C2    C3    C4    C5   C6   C7   C8  C9  C10
text  2     A     D     1    0    0    0   empty  
text  4     B     C     9    4    0    2   empty
text  5     A     B,D   5    3    0    0    4   0

我已经开始编写脚本,但我遇到了一些需要比较值和字母的问题。

这是我目前所拥有的:

my $table1 = prompt("Give the name of the file with variants:\n");
open(my $variants, '<',$table1) || die "Could not open file $table1 $!";

my $table2 = prompt("Give the name of the file with the frequencies: \n");
open(my $frequency, '<',$table2) || die "Could not open file $table2 $!";

my (@position, @A, @a, @B, @b, @C, @c, @D, @d); #instead of using hashes I was trying to put all the values in arrays, because I don't know how to hash multiple columns from a file.

while(<$frequency>){
    my @column = split(/\t/); # split on tabs
    $position[$_] .= "$column[1] "; # I want to assign the correct column values to the arrays
    $Afor[$_] .= "$column[2] ";
    $arev[$_] .= "$column[3] ";
    $Bfor[$_] .= "$column[4] ";
    $brev[$_] .= "$column[5] ";
    $Cfor[$_] .= "$column[6] ";
    $crev[$_] .= "$column[7] ";
    $Dfor[$_] .= "$column[8] ";
    $drev[$_] .= "$column[9] ";
}

while(<$variants>){
    next if /^\s*#/; # skipping some lines
    next if /^\s*"/;
    chomp;
my ($chr, $pos, $refall, $altall) = split;
} 

我不确定这是否是正确的方法,因为我现在不知道如何检查$frequencies 中的正确行和对应列。有人可以帮我吗?

【问题讨论】:

  • 您试图解释应该如何创建输出,但是如果您可以发布一个带有输入文件和预期输出的 complete 示例以便我们进行测试,这会容易得多我们的解决方案。
  • @amon 我更改了输入输出示例以更好地反映现实

标签: perl


【解决方案1】:

最重要的第一步通常是选择正确的数据结构来保存您的数据。为此,我认为频率文件内容的最简单结构是哈希数组。像这样:

use strict; use warnings;
use English '-no_match_vars';

my ($variants_file, $frequency_file) = @ARGV; # take filename from command line

open my $variants,  '<', $variants_file   or die "Could not open file $variants_file: $!";
open my $frequency, '<', $frequency_file  or die "Could not open file $frequency_file $!";

# parse the header fields
my (undef, undef, @header) = do {
  my $header_line = <$frequency>;
  chomp $header_line;
  split /\t/, $header_line;
};

my @frequency_data;
my $expect_pos = 1; # starting position
while (<$frequency>){
    chomp;
    my(undef, $pos, @column) = split /\t/; # split on tabs
    unless ($pos == $expect_pos) {
      die "On line $INPUT_LINE_NUMBER: expected data for position $expect_pos, instead found position $pos";
    }
    @{ $frequency_data[$pos] }{@header} = @column;
    ++$expect_pos;
}

那么就很容易通过位置和字母来访问频率数据了:

<$variants>;  # throw away header
while(<$variants>){
    next if /^\s*[#\"]/; # skipping some lines
    chomp;
    my ($text, $pos, $refall, $altall) = split;
    my @ref_data = @{ $frequency_data[$pos] }{$refall, lc($refall)};
    my @alt_data = @{ $frequency_data[$pos] }{$altall, lc($altall)};
    print join("\t", $text, $pos, @ref_data, @alt_data), "\n";
}

根据您的问题的最新编辑($variants 中的多个列),上述 sn-p 可以概括为:

<$variants>;
while (<$variants>) {
  next if ...
  chomp;
  my ($text, $pos, @cols) = split /\t/;
  my @data = map {@{ $frequency_data[$pos] }{$_, lc $_}}  # column to values
             map { split /,/ } @cols;                     # split cols at comma
  print join("\n", $text, $pos, @cols, @data), "\n";
}

我希望这会有所帮助。

【讨论】:

  • 很多语法错误并要求在所有@附近提供明确的包名称
  • @kdkeck Use English 'no-match vars'是什么意思?
  • @kdkeck 为什么现在使用$expect_pos 和$pos 而不是$position?
  • @user1987607 English 模块为所谓的标点符号变量提供了长名称。 $. 是行号,但英语为该变量提供了$INPUT_LINE_NUMBER。导入英语时的-no_match_vars 选项避免了对所有正则表达式匹配的运行时惩罚(由于不幸的设计事故,这是必要的)。我将名称更改为$expect_pos,因为它更好地传达了该变量的含义:这是我们期望的位置。
  • @user1987607 是的,这是一个额外的拆分——我是在 map 表达式中完成的。
猜你喜欢
  • 2020-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-27
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多