web-dev-qa-db-ja.com

ジェネリックリストの標準偏差?

汎用リストの標準偏差を計算する必要があります。コードを含めるようにします。その中のデータを含むその一般的なリスト。データは主にフロートと整数です。詳細を説明することなく、それに関連するコードを次に示します。

namespace ValveTesterInterface
{
    public class ValveDataResults
    {
        private List<ValveData> m_ValveResults;

        public ValveDataResults()
        {
            if (m_ValveResults == null)
            {
                m_ValveResults = new List<ValveData>();
            }
        }

        public void AddValveData(ValveData Valve)
        {
            m_ValveResults.Add(Valve);
        }

ここに標準偏差を計算する必要がある関数があります:

        public float LatchStdev()
        {

            float sumOfSqrs = 0;
            float meanValue = 0;
            foreach (ValveData value in m_ValveResults)
            {
                meanValue += value.LatchTime;
            }
            meanValue = (meanValue / m_ValveResults.Count) * 0.02f;

            for (int i = 0; i <= m_ValveResults.Count; i++) 
            {   
                sumOfSqrs += Math.Pow((m_ValveResults - meanValue), 2);  
            }
            return Math.Sqrt(sumOfSqrs /(m_ValveResults.Count - 1));

        }
    }
}

LatchStdev()関数内のwhatsは無視してください。これは間違いだと思います。 st devを計算しようとするのはまさに私の悪い試みです。私は、倍精度浮動小数点数型リストの方法を知っていますが、一般的なデータのリスト型ではありません。誰かがこれを経験したことがあるなら、助けてください。

55
Tom Hangler

この記事 は役立つはずです。 double値のシーケンスの偏差を計算する関数を作成します。必要なことは、適切なデータ要素のシーケンスを提供することだけです。

結果の関数は次のとおりです。

private double CalculateStdDev(IEnumerable<double> values)
{   
  double ret = 0;
  if (values.Count() > 0) 
  {      
     //Compute the Average      
     double avg = values.Average();
     //Perform the Sum of (value-avg)_2_2      
     double sum = values.Sum(d => Math.Pow(d - avg, 2));
     //Put it all together      
     ret = Math.Sqrt((sum) / (values.Count()-1));   
  }   
  return ret;
}

これは、計算される値のセレクタを提供する限り、任意のジェネリック型に適応するのに十分簡単です。 LINQはその点で優れています。Select関数を使用すると、カスタム型の汎用リストから標準偏差を計算する一連の数値を投影できます。

List<ValveData> list = ...
var result = list.Select( v => (double)v.SomeField )
                 .CalculateStdDev();
63
LBushkin

上記の例は少し間違っており、母集団セットが1の場合、ゼロ除算エラーが発生する可能性があります。次のコードはやや単純で、「母集団標準偏差」の結果が得られます。 ( http://en.wikipedia.org/wiki/Standard_deviation

using System;
using System.Linq;
using System.Collections.Generic;

public static class Extend
{
    public static double StandardDeviation(this IEnumerable<double> values)
    {
        double avg = values.Average();
        return Math.Sqrt(values.Average(v=>Math.Pow(v-avg,2)));
    }
}
146

受け入れられた答えは数学的には正しいように見えますが、プログラミングの観点からは間違っています。同じシーケンスを4回列挙します。基礎となるオブジェクトがリストまたは配列の場合は問題ないかもしれませんが、入力がフィルター処理/集約/などのlinq式である場合、またはデータがデータベースまたはネットワークストリームから直接来る場合、これによりパフォーマンスが大幅に低下します。

車輪を再発明せず、優れたオープンソースの数学ライブラリMath.NETの1つを使用することを強くお勧めします。私たちは会社でそのライブラリを使用しており、パフォーマンスに非常に満足しています。

PM>インストールパッケージMathNet.Numerics

var populationStdDev = new List<double>(1d, 2d, 3d, 4d, 5d).PopulationStandardDeviation();

var sampleStdDev = new List<double>(2d, 3d, 4d).StandardDeviation();

詳細については、 http://numerics.mathdotnet.com/docs/DescriptiveStatistics.html を参照してください。

最後に、可能な限り高速な結果を取得し、精度を犠牲にしたい場合は、「ワンパス」アルゴリズムをお読みください https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods

18
Yurik

私はあなたが何をしているのかを見て、似たようなものを使います。私はあなたが十分に行っていないようです。私は、すべてのデータ処理を単一のクラスにカプセル化する傾向があります。これにより、リストが変更されるまで計算される値をキャッシュできます。例えば:

public class StatProcessor{
private list<double> _data; //this holds the current data
private _avg; //we cache average here
private _avgValid; //a flag to say weather we need to calculate the average or not
private _calcAvg(); //calculate the average of the list and cache in _avg, and set _avgValid
public double average{
     get{
     if(!_avgValid) //if we dont HAVE to calculate the average, skip it
        _calcAvg(); //if we do, go ahead, cache it, then set the flag.
     return _avg; //now _avg is garunteed to be good, so return it.
     }
}
...more stuff
Add(){
//add stuff to the list here, and reset the flag
}
}

このメソッドを使用すると、平均の最初のリクエストのみが実際に平均を計算することに気付くでしょう。その後、リストから何かを追加(または削除、変更はしませんが、arntを表示)しない限り、基本的には何もしないで平均を取得できます。

さらに、平均は標準偏差のアルゴリズムで使用されるため、最初に標準偏差を計算すると無料で平均が得られ、最初に平均を計算すると標準偏差計算のパフォーマンスが少し向上します。フラグを確認してください。

さらに!とにかくすでにすべての値をループしている平均関数のような場所は、最小値や最大値などをキャッシュする絶好の機会です。もちろん、この情報の要求は、キャッシュされているかどうかを最初に確認する必要があります。リストを使用して最大値を見つけるのに比べて、相対的な速度低下を引き起こす可能性があります。あなたのアクセス。

0
Benjamin