11

是否有一些技巧可以让人们使用 bc (或其他一些标准实用程序)返回任意数量的数字的标准偏差?为方便起见,假设这些数字按以下方式存储在 Bash 变量中:

myNumbers="0.556
1.456
45.111
7.812
5.001"

因此,我正在寻找的答案将采用如下形式:

standardDeviation="$(echo "${myNumbers}" | <insert magic here>)"
4

5 回答 5

13

使用

standardDeviation=$(
    echo "$myNumbers" |
        awk '{sum+=$1; sumsq+=$1*$1}END{print sqrt(sumsq/NR - (sum/NR)**2)}'
)
echo $standardDeviation

使用

#!/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
于 2013-02-26T23:22:24.200 回答
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"))'
于 2016-01-17T10:42:25.263 回答
4

或者使用 GNU Octave(它可以比简单的 std 更多):

standardDeviation="$(echo "${myNumbers}" | octave --eval 'disp(std(scanf("%f")))')"
echo $standardDeviation

输出

18.742
于 2015-08-05T06:18:44.790 回答
1

鉴于:

$ myNumbers=$(echo "0.556 1.456 45.111 7.812 5.001" | tr " " "\n")

首先确定您是否需要这些数字的样本标准差总体标准差

总体标准差(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
于 2017-08-01T19:00:22.427 回答
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 
于 2021-03-16T11:51:44.947 回答