【问题标题】:Calculate the percentage difference between two adjacent rows uniquely唯一计算两个相邻行之间的百分比差异
【发布时间】:2013-12-23 00:47:31
【问题描述】:

我有一个制表符分隔的文件,例如

Name    S.No    Points  First
Jack    2   98  F
Jones   6   25
Mike    8   11
Jasmine 5   7   
Gareth  1   85  F
Simon   4   76
Mark    11  12
Steve   17  8
Clarke  3   7

我想计算前 3 名获得者以及 F 线表示的第一个获得者与该组中其他两个获得者之间的差值,该差异是该组中总分的平均值。例如,琼斯和迈克在第一种情况下,西蒙和马克在第二种情况下。我希望我的输出是

Name    S.No    Points  First
Jack    2   98  F
Jones   6   25  51.77
Mike    8   11  61.70
Gareth  1   85  F
Simon   4   76  4.78
Mark    11  12  44.68

计算百分比的公式在输出的最后一列是,例如案例1中的琼斯是

(Jack - Jones)*100/(Jack + Jones + Mike + Jasmine)
(98-25)*100/(98+25+11+7)= 51.77

我可以使用

选择前三行
awk '$NF~/E/{c=3;next}c-->0'

但是,计算差异和百分比有点麻烦,因为我必须在消除前三行之前对分母求和。

【问题讨论】:

  • 所以每个 F 开始一个新组(并标记要与其他组进行比较的组),并且您希望每个组的 F 记录和另外两个?总是以下两条记录吗?
  • 没错,F开始了一个新组,我想要以下两条记录

标签: python perl bash shell awk


【解决方案1】:

参考你的 awk 命令,似乎源文件已经按组对数据进行了排序。

awk 'NR==FNR{if ($NF=="F") {s=$1}; a[s]+=$3;next}
     { if (FNR=="1") {print;next}
       if ($NF=="F") {s=$1;b=$3;c=3;print;next}
       if (--c>0){ printf "%s %.2f\n", $0,(b-$3)*100/a[s];}
     }' file file

结果

Name    S.No    Points  First
Jack    2   98  F
Jones   6   25 51.77
Mike    8   11 61.70
Gareth  1   85  F
Simon   4   76 4.79
Mark    11  12 38.83

【讨论】:

    【解决方案2】:

    为 Mark 获取一个完全不同的号码:

    use 5.010;
    use strict;
    use warnings;
    use autodie;
    use List::Util 'sum';
    
    open my $infile, '<', 'foo.txt';
    my @groups;
    my $group; 
    while ( my $line = <$infile> ) {
        chomp $line;
        my ($name, $sno, $points, $first) = split /\t/, $line;
        if ( $first && $first eq 'F' ) {
            $group = [];
            push @groups, $group;
        }
        push @$group, { 'name' => $name, 'sno' => $sno, 'points' => $points, 'first' => $first };
    }
    
    say join "\t", qw/Name S.No Points First/;
    for my $group (@groups) {
        my $total_points = sum map $_->{'points'}, @$group;
        my $first_points = $group->[0]{'points'};
    
        say join "\t", @{ $group->[0] }{ qw/name sno points first/ };
    
        for my $other (1..2) {
            if ( $group->[$other] ) {
                say join "\t", @{ $group->[$other] }{ qw/name sno points/ }, sprintf "%.2f", 100 * ($first_points - $group->[$other]{'points'}) / $total_points;
            }
        }
    }
    

    产生:

    Name    S.No    Points  First
    Jack    2   98  F
    Jones   6   25  51.77
    Mike    8   11  61.70
    Gareth  1   85  F
    Simon   4   76  4.79
    Mark    11  12  38.83
    

    【讨论】:

      【解决方案3】:

      这是一个 awk 解决方案:

      awk -f c.awk input.txt input.txt
      

      c.awk 在哪里:

      NR==FNR {
          if ($NF=="F") {
              key1=$1
              A[key1]=$3
              B[key1]=$3
          }
          else if (key1)
              B[key1]+=$3
          next
      }
      key && NF==3 {
          if (++k<3) {
              $4=((A[key]-$3)*100)/B[key]
              print
          }
          next
      }
      
      $NF=="F" {
          key=$1
          k=0
      }
      
      {print}
      

      【讨论】:

      • 两遍文件是个好主意
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      相关资源
      最近更新 更多