【问题标题】:Using Shell tools (sed | awk... etc) to compute max, min and average field values from a given sample.dat file使用 Shell 工具 (sed | awk... 等) 从给定的 sample.dat 文件中计算最大、最小和平均字段值
【发布时间】:2013-05-10 11:02:45
【问题描述】:

我有一个 sample.dat 文件,其中包含 10 个不同的实验值 字段,随时间记录。使用 sedawk 或任何其他 shell 工具,我需要编写一个脚本,读取 sample.data 文件并为每个字段计算最大值、最小值和平均值。

sample.dat

字段1:实验1:10.0 字段2:实验1:12.5 字段1:实验2:5.0 字段 2:实验 2:14.0 字段1:实验3:18.0 字段2:实验3:3.5

输出

字段 1:MAX = 18.0,MIN = 5.0,AVERAGE = 11.0 字段 2:MAX = 14.0,MIN = 3.5,AVERAGE = 10.0

【问题讨论】:

  • 从每行中分离数字开始,然后你可以用它们进行任何计算......
  • 如果您有大量数据,最好使用 Perl。 Bash 对于测试操作可能会很慢。

标签: bash shell sed awk


【解决方案1】:
awk -F: '
{
    sum[$1]+=$3;
    if(!($1 in min) || (min[$1]>$3))
        min[$1]=$3;
    if(!($1 in max) || (max[$1]<$3))
        max[$1]=$3;
    count[$1]++
}
END {
  for(element in sum)
      printf("%s: MAX=%.1f, MIN=%.1f, AVARAGE=%.1f\n",
              element,max[element],min[element],sum[element]/count[element])
}' sample.dat

输出

field1: MAX=18.0, MIN=5.0, AVARAGE=11.0
field2: MAX=14.0, MIN=3.5, AVARAGE=10.0

【讨论】:

    【解决方案2】:

    这是我制作的 Perl 解决方案(将文件名替换为您使用的任何文件):

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use List::Util qw(max min sum);
    
    open( my $fh, "<", "sample.dat" ) or die $!;
    
    my %fields;
    while (<$fh>) {
        chomp;
        $_ =~ s/\s+//g;
        my @line = split ":";
        push @{ $fields{ $line[0] } }, $line[2];
    }
    
    close($fh);
    
    foreach ( keys %fields ) {
        print "$_: MAX="
          . max @{ $fields{$_} };
        print ", MIN="
          . min @{ $fields{$_} };
        print ", AVERAGE="
          . ( (sum @{ $fields{$_} }) / @{ $fields{$_} } ) . "\n";
    }
    

    【讨论】:

      【解决方案3】:

      bashbc

      #!/bin/bash
      
      declare -A min
      declare -A max
      declare -A avg
      declare -A avgCnt
      
      while read line; do
        key="${line%%:*}"
        value="${line##*: }"
        if [ -z "${max[$key]}" ]; then
          max[$key]="$value"
          min[$key]="$value"
          avg[$key]="$value"
          avgCnt[$key]=1
        else
          larger=`echo "$value > ${max[$key]}" | bc`
          smaller=`echo "$value < ${min[$key]}" | bc`
          avg[$key]=`echo "$value + ${avg[$key]}" | bc`
          ((avgCnt[$key]++))
          if [ "$larger" -eq "1" ]; then
            max[$key]="$value"
          fi
          if [ "$smaller" -eq "1" ]; then
            min[$key]="$value"
          fi
        fi
      done < "$1"
      
      for i in "${!max[@]}"
      do
        average=`echo "${avg[$i]} / ${avgCnt[$i]}" | bc`
        echo "$i: MAX = ${max[$i]}, MIN = ${min[$i]}, AVERAGE = $average"
      done
      

      【讨论】:

        【解决方案4】:

        你可以使用这个python代码:

        from collections import defaultdict
        d = defaultdict(list)
        [d[(line.split(":")[0])].append(float(line.split(":")[2].strip("\n "))) for line in open("sample.dat")]
        for f in d:  print f, ": MAX=", max(d[f]),", MIN=", min(d[f]),", AVG=", sum(d[f])/float(len(d[f]))
        

        【讨论】:

          【解决方案5】:

          你可以使用gnu-R 来做这样的事情:

          echo "1" > foo
          echo "2" >> foo
          
          cat foo \
          | r -e \
          ' 
            f <- file("stdin")
            open(f)
            
            v <- read.csv(f,header=F)
            write(max(v),stdout())
          '
          
          2
          

          对于汇总统计,

          cat foo \
          | r -e \
          ' 
            f <- file("stdin")
            open(f)
            
            v <- read.csv(f,header=F)
            write(summary(v),stdout())
          '
          
          # Max, Min, Mean, median, quartiles, deviation, etc.
          ...
          

          在 json 中:

          ... | r -e \
          '
            library(rjson)
            f <- file("stdin")
            open(f)
            v <- read.csv(f,header=F)
            json_summary <- toJSON(summary(v))
            write(json_summary,stdout())
          '
          
          # same stats 
          
          | jq '.Max'
          
          # for maximum
          
          

          如果您使用的是 linux 命令行环境,那么您可能不想重新实现轮子,保持矢量化,并且拥有易于阅读和开发的简洁代码,并且执行一些 标准的、可组合的功能

          在这种情况下,您不需要面向对象的语言(使用 python 会导致接口和代码膨胀,并使用 google、pip 和 conda 进行迭代,具体取决于您需要的库和您必须编码的类型转换)手),您不需要冗长的语法,并且您可能需要默认处理数字数据的数据框/向量/行/列。

          您可能还希望脚本可以在您的特定机器上毫无问题地浮动。如果你在 Linux 上,那可能意味着:gnu-R。通过apt-get安装依赖。

          【讨论】:

            猜你喜欢
            • 2017-10-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-03
            • 2016-11-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多