Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Perl中为两行数据查找不同的列_Perl - Fatal编程技术网

如何在Perl中为两行数据查找不同的列

如何在Perl中为两行数据查找不同的列,perl,Perl,我有6列这样的数据 LINES XY1 XY2 XY3 XY4 XY5 P1 Z/Z T/T -/- T/T T/T P2 A/A A/A G/G Z/Z T/T 1 G/G T/T G/G T/T G/G 2 T/T A/A C/C C/C T/T 3 T/T G/G T/T G/G T/T 4 A/A C/C A/A A/A A/A 5 A/A A/A T/T T/T A/A

我有6列这样的数据

LINES XY1  XY2  XY3  XY4  XY5
P1    Z/Z  T/T  -/-  T/T  T/T
P2    A/A  A/A  G/G  Z/Z  T/T
1     G/G  T/T  G/G  T/T  G/G
2     T/T  A/A  C/C  C/C  T/T
3     T/T  G/G  T/T  G/G  T/T
4     A/A  C/C  A/A  A/A  A/A
5     A/A  A/A  T/T  T/T  A/A
  • 我想找出哪些列(从
    XY1
    XY5
    )对于行
    P1
    P2
    是不同的。相等意味着
    P1
    P2
    包含相同的字母(等位基因),或者它们中的任何一个是
    Z/Z
    -/-

  • 我将比较
    1
    5
    行中的列与
    P2
    跨列
    XY1
    XY5
    。如果它们与输出匹配,则应包含
    1
    ,否则
    0
    。我继续这个过程,我的程序遇到了第二组
    P1
    P2

  • 我将计算从
    1
    5
    的行总数,仅包括
    P1
    P2
    之间不同的列

  • 我将通过将总和除以
    P1
    P2
    之间不同的列数来计算
    1
    5
    行的行百分比

  • 我期待这样的输出

    LINES XY1  XY2  XY3  XY4  XY5       
    P1    eq   nq   eq   eq   eq   SUM  %
    P2                                  1   
    1     0    0    1    0    0    0    0
    2     0    1    0    0    1    1    100
    3     0    0    0    0    1    0    0
    4     1    0    0    0    0    0    0
    5     1    1    0    0    0    1    100
    
    我有超过5000行的数据,目前我正在用不同的公式在Excel 2010中工作,但这占用了我很多精力

    我想用Perl来做这个,但我是Perl的新手。我已成功地将文件读取到屏幕上

    下面是我为文件读取部分编写的代码

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use Text::CSV;
    
    my $file = 'csv.csv';
    
    my $csv = Text::CSV->new();
    
    open(CSV, "<", $file) or die $!;
    
    while (<CSV>) {
      if ($csv->parse($_)) {
        my @columns = $csv->fields();
        print "@columns\n";
      }
      else {
        my $err = $csv->error_input;
        print "Failed to parse line: $err";
      }
    }
    
    close CSV;
    
    #/usr/bin/perl
    严格使用;
    使用警告;
    使用Text::CSV;
    my$file='csv.csv';
    my$csv=Text::csv->new();
    
    打开(CSV),此程序似乎可以执行您需要的操作。它需要输入文件的路径作为命令行上的参数。生成的输出将发送到
    STDOUT

    很多人不相信我的话,但使用
    Text::CSV
    解析制表符分隔的数据是错误的。它需要设置分隔符,并禁用引号和转义选项,如果操作正确,它最终的行为与
    split/\t/
    相同。您不能说数据是制表符分隔的还是空白分隔的ed,但由于您似乎没有包含空格的数据,因此我假设为后者。这种数据的解析非常简单,只需使用
    split

    它的工作原理是检查输入的每一行,查看它是
    P1
    行、
    P2
    行、编号行还是其他任何行(假定为标题行)

    • 当遇到标题行时,后续行的
      printf
      格式将从标题字段的间距导出,并将该行复制到输出

    • 当遇到
      P1
      行时,数据只需保存在
      @P1

    • 当遇到
      P2
      行时,数据保存在
      @P2
      中,以便与后续数据进行比较。适当的
      P1
      P2
      行将打印到输出中,并计算一个数组
      @enquality
      ,该数组包含
      P1
      数据不匹配的列的索引<代码>P2
    数据

  • 将编号的数据行逐列与保存在
    @p2
    中的数据进行比较,并相应地将
    1
    0
    插入相应的输出列中。
    $sum
    的值是通过将
    @不等
    数组中列出的输出列的值相加而计算出来的。百分比Age的计算方法是除以
    @enquality
    中的条目数,然后将数据打印到输出中

  • 注意

    不清楚“第二组P1和P2”是如何开始的,因此此代码可能无法正确处理它。您也没有说明要如何显示分数百分比,因此此代码只打印类似
    33.3333
    的内容

    另外,您没有说输出
    P2
    行末尾的
    1
    指示了什么,所以我只是照本宣科地复制了它

    use strict;
    use warnings;
    
    sub compare_alleles {
      return 1 if grep {$_ eq '-/-' or $_ eq 'Z/Z' } @_;
      return $_[0] eq $_[1] ? 1 : 0;
    }
    
    my $format;
    my (@p1, @p2);
    my @unequal;
    
    while (<>) {
    
      unless (/^(P?\d)/) {
        my @widths;
        push @widths, $+[1] - $-[1] while /(\S+\s*)/g;
        pop @widths;
        push @widths, $widths[-1], $widths[-1];
        $format = join '', map("%-${_}s", @widths, ''), "\n";
        print;
        next;
      }
    
      my @fields = split;
    
      if ($fields[0] eq 'P1') {
        @p1 = @fields;
      }
      elsif ($fields[0] eq 'P2') {
        @p2 = @fields;
        printf $format, 'P1', map (compare_alleles($p1[$_], $p2[$_]) ? 'eq' : 'nq', 1..5), 'SUM', '%';
        printf $format, 'P2', map('', 1..5), '', '1';
        @unequal = grep { not compare_alleles($p1[$_], $p2[$_]) } 1..5;
      }
      else {
        my @columns = ($fields[0], map { $fields[$_] eq $p2[$_] ? 1 : 0 } 1..5);
        my $sum = 0;
        $sum += $_ for @columns[@unequal];
        my $percent = $sum == 0 ? 0 : $sum * 100 / @unequal;
        printf $format, @columns, $sum, $percent;
      }
    }
    


    哇,这是一个很高的要求。你甚至没有说你的数据是否用制表符分隔。你使用了默认的逗号分隔符
    Text::CSV
    。亲爱的borodin非常感谢你的帮助。请忽略我在%计算中使用的P1和P2之间的NQ之和1。我在excel中的数据看起来像我的标题行(行,XY1到XY5)(这对于所有集合都是相同的)后面是带有P1(parent1)和P2(parent2)的行,后面是带有线条(脱离弹簧)的行,如此序列。第二个集合将继续这样,其结果为XY1到XY5(这些XY编号可能会在某一时间发生变化)。我想将%表示为4位数字,如89.94。在使用代码后,我在第19行的串联中遇到了类似使用未初始化的vlaue$uuu的错误。感谢您可以设置粘贴箱吗?如果您自己无法解决此问题,我需要查看确切的文件内容。还请显示您希望多个数据集的输出。@user2134713:请不要Don’不要试图通过编辑我的答案来扩展您的问题。您可以在问题中添加少量数据,也可以在上面创建一个页面并链接到该页面。亲爱的Borodin,感谢您的回复,这是pastebin的链接。我给出了三个父集合的示例数据,并且第一个集合的结果符合预期。希望我解释得很好。谢谢
    LINES XY1  XY2  XY3  XY4  XY5
    P1    eq   nq   eq   eq   eq   SUM  %
    P2                                  1
    1     0    0    1    0    0    0    0
    2     0    1    0    0    1    1    100
    3     0    0    0    0    1    0    0
    4     1    0    0    0    0    0    0
    5     1    1    0    0    0    1    100