首页 > 解决方案 > 具有不同行大小的多个文件的标准差

问题描述

我有几个不同行大小的文件,但每个文件中的列数是相同的。例如

ifile1.txt

1       1001    ?       ?
2       1002    ?       ?
3       1003    ?       ?
4       1004    ?       ?
5       1005    ?       0
6       1006    ?       1
7       1007    ?       3
8       1008    5       4
9       1009    3       11
10      1010    2       9

ifile2.txt

1       2001    ?       ?
2       2002    ?       ?
3       2003    ?       ?
4       2004    ?       ?
5       2005    ?       0
6       2006    6       12
7       2007    6       5
8       2008    9       10
9       2009    3       12
10      2010    5       7
11      2011    2       ?
12      2012    9       ?

ifile3.txt

1       3001    ?       ?
2       3002    ?       6
3       3003    ?       ?
4       3004    ?       ?
5       3005    ?       0
6       3006    1       25
7       3007    2       3
8       3008    ?       ?

在每个文件中,第一列表示索引号,第二列表示 ID。我想从第 3 列开始计算每个索引号的标准偏差。

所需的输出:

1       ?       ?          ----  [Here ? is computed from ?, ?, ?] So answer is ?
2       ?       ?          ----  [Here 6 is computed from ?, ?, 6] So answer is ? as only one sample
3       ?       ?
4       ?       ?
5       ?       0.00       ----- [Here 0 is computed from 0, 0, 0] So answer is as all are same value
6       3.54    12.01
7       2.83    1.15
8       2.83    4.24       ----- [Here 7 is computed from 5, 9, ?]
9       0.00    0.71
10      2.12    1.41
11      ?       ?
12      ?       ?

我正在尝试更改以下适用于平均值的脚本(从具有不同行大小的多个文件的平均值复制)

{
    c = NF
    if (r<FNR) r = FNR
    
    for (i=3;i<=NF;i++) {
        if ($i != "?") {
            s[FNR "," i] += $i
            n[FNR "," i] += 1
        }
    }
}

END {
    for (i=1;i<=r;i++) {
        printf("%s\t", i)
        for (j=3;j<=c;j++) {
            if (n[i "," j]) {
                printf("%.1f\t", s[i "," j]/n[i "," j])
            } else {
                printf("?\t")
            }
        }
        printf("\n")
    }
}

  

我了解我需要使用以下内容修改脚本,但无法做到这一点。

          mean=s[i "," j]/n[i "," j]
          for (i=1; i in array ; i++)
            sqdif+=(array[i]-mean)**2
             printf("%.1f\t", sqdif/(n[i "," j]-1)**0.5)

标签: shellawkstandard-deviation

解决方案


您需要将第 3 列的原始数字保存到 NF 以计算标准。您可以尝试的一种方法是将它们连接到数组值中(参见v下面的代码),然后在 END 块的最终计算中进行拆分以检索它们,例如:

$ cat test.awk

{
  nMax = FNR > nMax ? FNR : nMax                        # get the max FNR from all files
  for (j=3; j<=NF; j++) {
    if ($j == "?") continue
    v[FNR, j] = v[FNR, j] == "" ? $j : v[FNR, j] FS $j  # concatenate values of (FNR,j) in `v` using FS
    t[FNR, j] += $j                                     # calculate total for each (FNR,j)
  }
}
END {
  for (i=1; i<=nMax; i++) {
    printf("%d\t", i)
    for (j=3; j<=NF; j++) {
      if ((i,j) in t) {         # if (i,j) exists, split v into vals using default FS
        n = split(v[i,j], vals)
        if (n == 1) {           # print "?" if only 1 item in array vals
          printf("?")
        } else {                # otherwise, calculate mean `e`, sum `s` and then std
          e = t[i,j]/n
          s = 0
          for(x in vals) s += (vals[x]-e)**2
          printf("%.2f", sqrt(s/(n-1)))
        }
      } else { # print "?" if (i,j) not exists
        printf("?")
      }
      printf(j==NF?"\n":"\t")
    }
  }
}

运行上述代码的结果:

$ awk -f test.awk ifile*.txt
1       ?       ?
2       ?       ?
3       ?       ?
4       ?       ?
5       ?       0.00
6       3.54    12.01
7       2.83    1.15
8       2.83    4.24
9       0.00    0.71
10      2.12    1.41
11      ?       ?
12      ?       ?

推荐阅读