使用 awk 的标准差

使用 awk 的标准差

我使用下面的命令来获取文件 A 名称的标准偏差

   1 2 3 平均
23.3107 20.0372 21.7236 21.6905

awk '{x[NR]=$0 ;} END{a=$4; for (i in x){ss += (x[i]-a)^2} sd = sqrt(ss/n);打印 $5 = sd}'

变得致命:尝试除以零

将上面的命令修改为

awk '{x[NR]=$0 ;} END{a=$4; for (i in x){if (a == 0) $6 ="N/A";否则 ss += (x[i]-a)^2} sd = sqrt(ss/n);打印 $5 = sd}'

但错误仍然存​​在?谢谢 cas 理解我的追求?

答案1

“n”在哪里?

你写:

sd = sqrt(ss/n)

但是你在代码中的哪里分配了变量“n”?从表面awk上看,“n”为零。

另外,第 5 列在哪里a=$5(第三个问题,为什么这个作业在这个END部分)?您的示例仅包含 4 列。

答案2

你想做这样的事情吗?这是我能想到的理解你的剧本的唯一方法。

awk -v OFS=$'\t' '
FNR == 1 { $5 = "sdev" ; print }

FNR > 1  { a = $4    # field 4 is 'avg'
           n = NF-1  # exclude the 'avg' field from the ss calculations.

           for (i=1; i <= n; i++) { ss += ($i - a)^2 } 

           $5 = sqrt(ss/n)
           print
         }' inputfile

注意:$i线上for不是指 的值i,而是指编号的输入字段i- 即它循环遍历$1$2$3。这对于 shell 或用户来说可能并不明显,perl因为(标量)变量通常以 为前缀$

NF是一行中的字段数,并且FNR是当前输入文件的记录(行)号(因此此awk脚本支持多个输入文件,每个文件都有自己的标题行。如果在某一处只有一个输入文件时间,您可以使用)NR代替FNR

示例输出:

1       2       3       avg     sdev
23.3107 20.0372 21.7236 21.6905 1.33661

这是另一个版本,适用于每行任意数量的字段。它假设最后的一行的字段包含该行上所有先前字段的平均值。

$NF指的是最后一个字段的值(即“avg”)并$new指的是(最后一个字段+ 1),即为其分配一个值会在行尾添加一个新字段。

awk -v OFS=$'\t' '
FNR == 1 { new = NF+1   # number of new field to add
           $new = "sdev"
           print 
         }

FNR > 1  { a = $NF   # last field is 'avg'
           n = NF-1  # exclude the 'avg' field from the ss calculations.

           for (i=1; i <= n; i++) { ss += ($i - a)^2 } 

           $new = sqrt(ss/n)
           print
         }' inputfile

每个输入行有 5 个值加上平均值的示例输出:

1       2       3       4       5       avg     sdev
23.3107 20.0372 21.7236 20.5328 21.2016 21.3611 1.13107

相关内容