awk:如何计算csv中列的子集平均值?

时间:2015-02-04 23:58:18

标签: csv awk

我有一个非常大的CSV文件,其内容如下:

#       col1    col2    col3
1       1       7       9
2       2       8       10
3       3       9       11
4       4       10      12
5       5       11      13
6       6       12      14

对于所有列,我想计算每个连续两个字段的平均值,然后偏移到接下来的两个字段。例如,col1平均值12是结果列的第一个单元格,3和{{1}的平均值}}是结果列的第二个单元格。因此,新列大小原来4的一半

对于上面提供的示例文件,脚本的输出应如下所示:

col1

这个问题似乎是一个很好的[一]用AWK解决,但我仍然是使用AWK的新手。

任何指针都表示赞赏。

2 个答案:

答案 0 :(得分:2)

可以使用awk完成。

awk 'BEGIN   { OFS = "\t" }
     NR  ==1 { print; next } # Print header
     NR%2==0 { for (i = 2; i <= NF; i++) old[i] = $i; }
     NR%2==1 { for (i = 2; i <= NF; i++) $i = ($i + old[i])/2
               $1 = (NR-1)/2; print }'
  1. 将输出字段分隔符设置为tab。
  2. 打印标题行并跳至下一行。
  3. 对于偶数行,将字段2中的值保存到old数组中的末尾。
  4. 对于奇数行(在第一行之后),计算旧字段值和当前字段值的平均值。设置行号。打印结果。
  5. 示例输出:

    #       col1    col2    col3
    1       1.5     7.5     9.5
    2       3.5     9.5     11.5
    3       5.5     11.5    13.5
    

    对N行

    组进行推广

    此脚本接受一个参数,该参数是要组合在一起的行数,如果未指定参数,则默认为2。如评论中所述,代码需要将old数组值重置为0,并对值求和而不是赋值。

    $ cat x.awk
    awk -v N=${1:-2} \
        'BEGIN   { OFS = "\t" }
         NR  ==1 { print; next } # Print header
         NR%N!=1 { for (i = 2; i <= NF; i++) old[i] += $i }
         NR%N==1 { for (i = 2; i <= NF; i++) $i = ($i + old[i])/N
                   $1 = int((NR-1)/N)
                   print
                   for (i = 2; i <= NF; i++) old[i] = 0
                 }' data
    $ cat data
    #       col1    col2    col3
    1       1       7       9
    2       2       8       10
    3       3       9       11
    4       4       10      12
    5       5       11      13
    6       6       12      14
    7       7       14      17
    8       8       16      19
    9       9       18      22
    10      10      20      26
    11      11      22      28
    12      12      24      29
    $ bash x.awk 2
    #       col1    col2    col3
    1       1.5     7.5     9.5
    2       3.5     9.5     11.5
    3       5.5     11.5    13.5
    4       7.5     15      18
    5       9.5     19      24
    6       11.5    23      28.5
    $ bash x.awk 3
    #       col1    col2    col3
    1       2       8       10
    2       5       11      13
    3       8       16      19.3333
    4       11      22      27.6667
    $ bash x.awk 4
    #       col1    col2    col3
    1       2.5     8.5     10.5
    2       6.5     13.25   15.75
    3       10.5    21      26.25
    $ bash x.awk 6
    #       col1    col2    col3
    1       3.5     9.5     11.5
    2       9.5     19      23.5
    $
    

    如果您希望在末尾打印出部分组,请添加一个适当的END块,该块需要除以部分行数而不是行数。

答案 1 :(得分:1)

我冒昧地将Jonathan Leffler的答案概括为Nth案例,以了解平均窗口和偏移量的大小。

我写了一个awk脚本(我称之为avewithoffset),如下所示:

#!bin/awk
BEGIN{
    FS=OFS="\t";
    n=5; }
NR==1 { print; next;}
(NR-1)%n!=0 { for (i = 2; i <= NF; i++) old[i] += $i; }
(NR-1)%n==0 { for (i = 2; i <= NF; i++)
              { $i = ($i + old[i])/n; old[i] = 0; }
              $1 = int( (NR-1)/n );
              print; }

注意 n=5

我将以下文件提供给它:

#   col1    col2    col3
1   1       16      31
2   2       17      32
3   3       18      33
4   4       19      34
5   5       20      35
6   6       21      36
7   7       22      37
8   8       23      38
9   9       24      39
10  10      25      40
11  11      26      41
12  12      27      42
13  13      28      43
14  14      29      44
15  15      30      45

结果文件如下:

#   col1    col2    col3
1   3       18      33
2   8       23      38
3   13      28      43