我有一个包含很多标签的文件,标签旁边有一个数字,如下所示:
<Score>4
... other data
<Score>2
... other data
<Score>3
等等...
我使用 grep 来获取一行中出现的次数
grep -c '<Score>' $1
我使用 awk 计算了分数的总和:
awk 'sub(/<Score>/,""){y+=$0} END{print y}' $1}
然后将其除以我从 grep 得到的数字以获得平均值。
我正在努力解决的是如何从 <Score> 旁边的每个值中取出平均值,将其平方,然后将它们加在一起。
平均值存储在变量 $mean 中我尝试过的代码如下所示:
awk 'sub(/<Score>/,""){y+=($0-$mean)^2} END{print y}' $1
然而它一直输出 0,如果我可以将其存储在变量中,那么我将能够使用所有其他变量来计算标准差。
答案1
这里有一些实用程序供您使用。第一个计算给它的数字的平均值(每行一个数字)。第二个使用第一个来计算文件中数字的标准偏差。
可执行文件average
:
#!/usr/bin/awk -f
/^[0-9.+-]/ { sum += $0; ++n }
END { print sum / n }
该awk
脚本将从文件或标准输入读取输入并计算其中数字的平均值。它期望每行一个数字。
可执行文件stdev
:
#!/bin/sh
awk -v avg="$( ./average "$1" )" \
'/^[0-9.+-]/ { sum += ($0 - avg)^2; ++n }
END { print sqrt(sum / (n - 1)) }' "$1"
该 shell 脚本将首先使用上述average
脚本来计算命令行上给出的文件中数据的平均值。该数字被分配给awk
变量avg
。然后,它使用与脚本相同类型的数字检测average
来计算标准差。
由于这个脚本是现在编写的,因此它需要来自文件的数据,而不是标准输入的数据。
在数据上使用它的一种方法:
sed -n '/^<Score>/s///p' input.dat >output.dat
使用给定的数据,这将生成一个名为的文件,output.dat
其中包含以下内容:
4
2
3
stdev
在此文件上使用上面的脚本:
$ ./stdev output.dat
1
据我所知,这是正确的。
当然,您awk
也可以直接在一次调用中完成此操作,而无需构建任何类型的可重用工具:
awk -F '>' '/^<Score>/ { v[++n] = $2; s += $2 }
END { avg = s/n;
for (i=1; i<=n; ++i) {
std += (v[i] - avg)^2;
}
print sqrt(std / (n - 1));
}' input.dat