是否有一些技巧可以让人们使用bc(或其他一些标准实用程序)来返回任意数量的数字的标准偏差?为方便起见,假设数字以下列方式存储在Bash变量中:
myNumbers="0.556
1.456
45.111
7.812
5.001"
所以,我正在寻找的答案将采用以下形式:
standardDeviation="$(echo "${myNumbers}" | <insert magic here>)"
答案 0 :(得分:11)
使用awk:
standardDeviation=$(
echo "$myNumbers" |
awk '{sum+=$1; sumsq+=$1*$1}END{print sqrt(sumsq/NR - (sum/NR)**2)}'
)
echo $standardDeviation
使用perl:
#!/usr/bin/env perl
use strict; use warnings;
use Math::NumberCruncher;
my @data = qw/
0.556
1.456
45.111
7.812
5.001
/;
print Math::NumberCruncher::StandardDeviation(\@data);
16.7631
答案 1 :(得分:5)
人口标准差:
jq -s '(add/length)as$a|map(pow(.-$a;2))|add/length|sqrt'
ruby -e'a=readlines.map(&:to_f);puts (a.map{|x|(x-a.reduce(:+)/a.length)**2}.reduce(:+)/a.length)**0.5'
jq -s '(map(.*.)|add/length)-pow(add/length;2)|sqrt'
awk '{x+=$0;y+=$0^2}END{print sqrt(y/NR-(x/NR)^2)}'
在awk
中,^
在POSIX中,但**
不在。 **
和gawk
支持nawk
,但mawk
不支持length
。
示例标准差(前两个命令与上面的前两个命令相同,但length-1
已替换为jq -s '(add/length)as$a|map(pow(.-$a;2))|add/(length-1)|sqrt'
ruby -e'a=readlines.map(&:to_f);puts (a.map{|x|(x-a.reduce(:+)/a.length)**2}.reduce(:+)/(a.length-1))**0.5'
R -q -e 'sd(scan("stdin"))'
):
std::function
答案 2 :(得分:4)
或者使用GNU Octave(它可以比简单的std更多):
standardDeviation="$(echo "${myNumbers}" | octave --eval 'disp(std(scanf("%f")))')"
echo $standardDeviation
输出
18.742
答案 3 :(得分:1)
假设:
$ myNumbers=$(echo "0.556 1.456 45.111 7.812 5.001" | tr " " "\n")
首先确定您是否需要sample standard deviation vs population standard deviation这些数字。
人口标准差(Excel中的函数STDEV.P)需要整个数据填充。在Excel中,将跳过文本或空格。
在awk
:
$ echo "$myNumbers" | awk '$1+0==$1 {sum+=$1; sumsq+=$1*$1; cnt++}
END{print sumsq/cnt; print sqrt(sumsq/cnt - (sum/cnt)**2)}'
16.7631
或Ruby
:
$ echo "$myNumbers" | ruby -e 'arr=$<.read.split(/\s/).map { |e| Float(e) rescue nil }.compact
sumsq=arr.inject(0) { |acc, e| acc+=e*e }
p (sumsq/arr.length - (arr.sum/arr.length)**2)**0.5'
16.76307799182477
对于样本标准差(Excel中的函数STDEV.S并忽略文本或空白)您需要先收集整个样本,因为对样本中的每个值使用均值。
在awk
:
$ echo "$myNumbers" |
awk 'function sdev(array) {
for (i=1; i in array; i++)
sum+=array[i]
cnt=i-1
mean=sum/cnt
for (i=1; i in array; i++)
sqdif+=(array[i]-mean)**2
return (sqdif/(cnt-1))**0.5
}
$1+0==$1 {sum1[++cnt]=$1}
END {print sdev(sum1)}'
18.7417
或者在Ruby中:
$ ruby -lane 'BEGIN{col1=[]}
col1 << Float($F[0]) rescue nil
END {col1.compact
mean=col1.sum / col1.length
p (col1.inject(0){ |acc, e| acc+(e-mean)**2 } /
(col1.length-1))**0.5
}' <(echo "$myNumbers")
18.741690950925424
答案 4 :(得分:0)
只是为了好玩,8 年后,使用 gnuplot:
echo "${myNumbers}" | gnuplot -e 'stats "-" nooutput; print STATS_stddev'
16.7630779918248
作为解释,我让 gnuplot 对其 stats
上的数据运行 stdin
函数,抑制正常输出并仅打印标准偏差。
相关,但不是答案的一部分……您还可以生成许多其他统计数据,例如中值、峰态和偏斜、四分位数、最大值、最小值,如下所示:
echo "${myNumbers}" | gnuplot -e 'stats "-"'
样本输出
* FILE:
Records: 5
Out of range: 0
Invalid: 0
Header records: 0
Blank: 0
Data Blocks: 1
* COLUMN:
Mean: 11.9872
Std Dev: 16.7631
Sample StdDev: 18.7417
Skewness: 1.4125
Kurtosis: 3.1303
Avg Dev: 13.2495
Sum: 59.9360
Sum Sq.: 2123.4687
Mean Err.: 7.4967
Std Dev Err.: 5.3010
Skewness Err.: 1.0954
Kurtosis Err.: 2.1909
Minimum: 0.5560 [0]
Maximum: 45.1110 [2]
Quartile: 1.4560
Median: 5.0010
Quartile: 7.8120