28

我有一个包含 24(行)x 16(列)数据的“file.dat”。

我已经测试了以下计算每列的平均值的 awk 脚本。

touch aver-std.dat
awk '{   for (i=1; i<=NF; i++) { sum[i]+= $i } }
END { for (i=1; i<=NF; i++ )  
{ printf "%f \n", sum[i]/NR} }' file.dat >> aver-std.dat

输出“aver-std.dat”有一列包含这些平均值。

与平均计算类似,我想计算数据文件“file.dat”每一列的标准偏差,并将其写入输出文件的第二列。也就是说,我想要一个输出文件,其中第一列中的平均值和第二列中的标准偏差。

我一直在做不同的测试,比如这个

touch aver-std.dat
awk '{   for (i=1; i<=NF; i++) { sum[i]+= $i }}
END { for (i=1; i<=NF; i++ )  
{std[i] += ($i - sum[i])^2 ; printf "%f %f \n", sum[i]/NR, sqrt(std[i]/(NR-1))}}' file.dat >> aver-std.dat

它在第二列中写入值,但它们不是标准偏差的正确值。偏差的计算在某种程度上是不正确的。我将非常感谢任何帮助。问候

4

4 回答 4

33

标准差是

stdev = sqrt((1/N)*(sum of (value - mean)^2))

但是还有另一种形式的公式不需要你事先知道平均值。这是:

stdev = sqrt((1/N)*((sum of squares) - (((sum)^2)/N)))

(如果您有兴趣,可以在网上快速搜索标准差的“平方和”公式,即可得出推导)

要使用此公式,您需要跟踪值的总和和平方和。因此,您的 awk 脚本将更改为:

    awk '{for(i=1;i<=NF;i++) {sum[i] += $i; sumsq[i] += ($i)^2}} 
          END {for (i=1;i<=NF;i++) {
          printf "%f %f \n", sum[i]/NR, sqrt((sumsq[i]-sum[i]^2/NR)/NR)}
         }' file.dat >> aver-std.dat
于 2013-09-13T12:47:33.730 回答
24

To simply calculate the population standard deviation of a list of numbers, you can use a command like this:

awk '{x+=$0;y+=$0^2}END{print sqrt(y/NR-(x/NR)^2)}'

Or this calculates the sample standard deviation:

awk '{sum+=$0;a[NR]=$0}END{for(i in a)y+=(a[i]-(sum/NR))^2;print sqrt(y/(NR-1))}'

^ is in POSIX. ** is supported by gawk and nawk but not by mawk.

于 2016-01-17T11:04:23.403 回答
4

以下是我对研磨机数据输出文件进行的一些计算,以进行必须中断的长时间浸泡测试:

标准偏差(有偏)+平均值:

cat <grinder_data_file> | grep -v "1$" | awk -F ', '  '{   sum=sum+$5 ; sumX2+=(($5)^2)} END { printf "Average: %f. Standard Deviation: %f \n", sum/NR, sqrt(sumX2/(NR) - ((sum/NR)^2) )}'

标准偏差(无偏)+平均值:

cat <grinder_data_file>  | grep -v "1$" | awk -F ', '  '{   sum=sum+$5 ; sumX2+=(($5)^2)} END { avg=sum/NR; printf "Average: %f. Standard Deviation: %f \n", avg, sqrt(sumX2/(NR-1) - 2*avg*(sum/(NR-1)) + ((NR*(avg^2))/(NR-1)))}'
于 2014-06-18T12:14:18.960 回答
-1

您的脚本应该以某种方式采用这种形式:

awk '{
    sum = 0
    for (i=1; i<=NF; i++) {
        sum += $i
    }
    avg = sum / NF
    avga[NR] = avg
    sum = 0
    for (i=1; i<=NF; i++) {
        sum += ($i - avg) ^ 2
    }
    stda[NR] = sqrt(sum / NF)
}

END { for (i = 1; i in stda; ++i) { printf "%f %f \n", avga[i], stda[i] } }' file.dat >> aver-std.dat
于 2013-09-13T12:35:28.887 回答