一連の数値と比較した数値が、平均値から 1 stddev の範囲外にあるかどうかを知る必要があります。
12 に答える
二乗和アルゴリズムはほとんどの場合問題なく機能しますが、非常に大きな数を扱う場合は大きな問題を引き起こす可能性があります。あなたは基本的に負の分散で終わるかもしれません...
さらに、a^2 を pow(a,2) として計算しないでください。a * a の方がほぼ確実に高速です。
標準偏差を計算する最良の方法は、ウェルフォード法です。私のCは非常にさびていますが、次のようになります。
public static double StandardDeviation(List<double> valueList)
{
double M = 0.0;
double S = 0.0;
int k = 1;
foreach (double value in valueList)
{
double tmpM = M;
M += (value - tmpM) / k;
S += (value - tmpM) * (value - M);
k++;
}
return Math.Sqrt(S / (k-2));
}
(標本集団ではなく) 母集団全体がある場合は、 を使用します。return Math.Sqrt(S / (k-1));
編集:ジェイソンの発言に従ってコードを更新しました...
編集:アレックスの発言に従ってコードも更新しました...
ハイメのソリューションよりも10倍高速ですが、ハイメが指摘したように、次のことに注意してください。
「二乗和アルゴリズムはほとんどの場合問題なく機能しますが、非常に大きな数を扱っている場合は大きな問題を引き起こす可能性があります。基本的に負の分散になる可能性があります」
非常に大きな数または非常に大量の数を扱っていると思われる場合は、両方の方法を使用して計算する必要があります。結果が等しい場合は、「my」方法を使用できることがわかります。
public static double StandardDeviation(double[] data)
{
double stdDev = 0;
double sumAll = 0;
double sumAllQ = 0;
//Sum of x and sum of x²
for (int i = 0; i < data.Length; i++)
{
double x = data[i];
sumAll += x;
sumAllQ += x * x;
}
//Mean (not used here)
//double mean = 0;
//mean = sumAll / (double)data.Length;
//Standard deviation
stdDev = System.Math.Sqrt(
(sumAllQ -
(sumAll * sumAll) / data.Length) *
(1.0d / (data.Length - 1))
);
return stdDev;
}
最後の行でk-2で割る必要があることを除いて、ハイメが受け入れた答えは素晴らしいです(「number_of_elements-1」で割る必要があります)。さらに良いことに、k を 0 から開始します。
public static double StandardDeviation(List<double> valueList)
{
double M = 0.0;
double S = 0.0;
int k = 0;
foreach (double value in valueList)
{
k++;
double tmpM = M;
M += (value - tmpM) / k;
S += (value - tmpM) * (value - M);
}
return Math.Sqrt(S / (k-1));
}
平均と平均二乗を累積することで、データを 2 回パスすることを避けることができます。
cnt = 0
mean = 0
meansqr = 0
loop over array
cnt++
mean += value
meansqr += value*value
mean /= cnt
meansqr /= cnt
と成形
sigma = sqrt(meansqr - mean^2)
多くの場合、係数cnt/(cnt-1)
も適切です。
ところで-- DemiとMcWafflestixの回答のデータに対する最初のパスは、への呼び出しに隠されていますAverage
。そのようなことは小さなリストでは確かに些細なことですが、リストがキャッシュのサイズ、またはワーキング セットのサイズを超えた場合、これは入札取引になります。
コードスニペット:
public static double StandardDeviation(List<double> valueList)
{
if (valueList.Count < 2) return 0.0;
double sumOfSquares = 0.0;
double average = valueList.Average(); //.NET 3.0
foreach (double value in valueList)
{
sumOfSquares += Math.Pow((value - average), 2);
}
return Math.Sqrt(sumOfSquares / (valueList.Count - 1));
}
Rob の役立つ回答は、私が Excel を使用して見たものと完全には一致しないことがわかりました。Excel と一致させるために、valueList の Average を StandardDeviation 計算に渡しました。
これが私の2セントです...そして明らかに、関数内のvalueListから移動平均(ma)を計算できます-しかし、たまたま、標準偏差が必要になる前にすでに持っています。
public double StandardDeviation(List<double> valueList, double ma)
{
double xMinusMovAvg = 0.0;
double Sigma = 0.0;
int k = valueList.Count;
foreach (double value in valueList){
xMinusMovAvg = value - ma;
Sigma = Sigma + (xMinusMovAvg * xMinusMovAvg);
}
return Math.Sqrt(Sigma / (k - 1));
}
/// <summary>
/// Calculates standard deviation, same as MATLAB std(X,0) function
/// <seealso cref="http://www.mathworks.co.uk/help/techdoc/ref/std.html"/>
/// </summary>
/// <param name="values">enumumerable data</param>
/// <returns>Standard deviation</returns>
public static double GetStandardDeviation(this IEnumerable<double> values)
{
//validation
if (values == null)
throw new ArgumentNullException();
int lenght = values.Count();
//saves from devision by 0
if (lenght == 0 || lenght == 1)
return 0;
double sum = 0.0, sum2 = 0.0;
for (int i = 0; i < lenght; i++)
{
double item = values.ElementAt(i);
sum += item;
sum2 += item * item;
}
return Math.Sqrt((sum2 - sum * sum / lenght) / (lenght - 1));
}
これは人口標準偏差です
private double calculateStdDev(List<double> values)
{
double average = values.Average();
return Math.Sqrt((values.Select(val => (val - average) * (val - average)).Sum()) / values.Count);
}
サンプル標準偏差については、上記のコードで [values.Count] を [values.Count -1] に変更するだけです。
セット内のデータ ポイントが 1 つだけにならないようにしてください。