11

だから私はコンパス角度 (度) を使用してアプリケーションに取り組んでいます。以下を使用して、角度の平均の計算を決定することができました(http://en.wikipedia.org/wiki/Directional_statistics#The_fundamental_difference_between_linear_and_circular_statisticsにあります):

 double calcMean(ArrayList<Double> angles){
      double sin = 0;
      double cos = 0;
      for(int i = 0; i < angles.size(); i++){
           sin += Math.sin(angles.get(i) * (Math.PI/180.0));
           cos += Math.cos(angles.get(i) * (Math.PI/180.0)); 
      }
      sin /= angles.size();
      cos /= angles.size();

      double result =Math.atan2(sin,cos)*(180/Math.PI);

      if(cos > 0 && sin < 0) result += 360;
      else if(cos < 0) result += 180;

      return result;
 }

したがって、平均値/平均値は正しく取得できますが、適切な分散/標準偏差値を取得できません。分散を間違って計算していることは確かですが、それを行う正しい方法が思いつきません。

分散を計算する方法は次のとおりです。

 double calcVariance(ArrayList<Double> angles){

      //THIS IS WHERE I DON'T KNOW WHAT TO PUT
      ArrayList<Double> normalizedList = new ArrayList<Double>();
      for(int i = 0; i < angles.size(); i++){
           double sin = Math.sin(angles.get(i) * (Math.PI/180));
           double cos = Math.cos(angles.get(i) * (Math.PI/180));
           normalizedList.add(Math.atan2(sin,cos)*(180/Math.PI));
      }

      double mean = calcMean(angles);
      ArrayList<Double> squaredDifference = new ArrayList<Double>();
      for(int i = 0; i < normalizedList.size(); i++){
           squaredDifference.add(Math.pow(normalizedList.get(i) - mean,2));
      }

      double result = 0;
      for(int i = 0; i < squaredDifference.size(); i++){
           result+=squaredDifference.get(i);
      }

      return result/squaredDifference.size();
 }

これは分散を計算する適切な方法ですが、私が使用することになっている方法ではありません。逆正接を使用することになっていると思いますが、標準偏差/分散の値がずれているようです。ヘルプ?

編集: 例: 値 0,350,1,0,0,0,1,358,9,1 を入力すると、平均角度が 0.0014 になります (角度がゼロに非常に近いため)。 、あなたは72を取得します...これはかなり外れています。個々の値をあるべき値に操作する方法がわからないため、計算された分散は 25074 であり、標準偏差は 158 度になります。これは正気ではありません!! (ほんの数度である必要があります)私がする必要があると思うのは、個々の値を適切に正規化して、正しい分散/標準偏差値を取得できるようにすることです。

4

5 に答える 5

16

ウィキペディアのページsqrt(-log R²)で、サンプルを単位円上の複素数と見なす場合、円形標準偏差は にリンクしています。ここで、R = |サンプルの平均| です。したがって、標準偏差の計算は平均角度の計算と非常によく似ています。

double calcStddev(ArrayList<Double> angles){
      double sin = 0;
      double cos = 0;
      for(int i = 0; i < angles.size(); i++){
           sin += Math.sin(angles.get(i) * (Math.PI/180.0));
           cos += Math.cos(angles.get(i) * (Math.PI/180.0)); 
      }
      sin /= angles.size();
      cos /= angles.size();

      double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));

      return stddev;
 }

少し考えてみると、それは理にかなっています。単位円上で互いに近い点の束を平均すると、結果は円からそれほど離れていないため、R は 1 に近くなり、stddev は近くなります。 0. ポイントが円に沿って均等に分布している場合、それらの平均は 0 に近いため、R は 0 に近くなり、stddev は非常に大きくなります。

于 2012-12-18T15:36:46.143 に答える
1

数学ライブラリ関数の剰余は、角度を扱うのに便利です。

簡単な変更は、置き換えることです

normalizedList.get(i) - mean

remainder( normalizedList.get(i) - mean, 360.0)

ただし、残りの呼び出しがすべての正規化を処理するため、最初のループは冗長です。さらに、それらを保存するよりも、平方差を合計する方が簡単です。個人的には、算術ができる場合は pow() を避けるのが好きです。したがって、関数は次のようになります。

double calcVariance(ArrayList<Double> angles){
 double mean = calcMean(angles);

  double result = 0;
  for(int i = 0; i < angles.size(); i++){
   double diff = remainder( angles.get(i) - mean, 360.0);
        result += diff*diff;
  }

  return result/angles.size();
 }
于 2012-12-18T11:31:24.113 に答える
1

Math.atan(sin/cosine)を使用すると、-90 ~ 90 度の角度が得られます。角度が 120 度の場合、cos =-0.5、sin =0.866、atan(-1.7) =-60 度になります。したがって、正規化されたリストに間違った角度を入れます。

分散が線形偏差であると仮定すると、角度配列を-calcMean(angles)で回転させ、 180/-180 より上/下の角度に 360 を加算/減算することをお勧めします (私の文章をくそー!)) を見つけながら最大角度と最小角度。それはあなたに望ましい偏差を与えます。このような:

    Double meanAngle = calcMean(angles)
    Double positiveDeviation = new Double(0);
    Double negativeDeviation = new Double(0);
    Iterator<Double> it = angles.iterator();
    while (it.hasNext())
    {
        Double deviation = it.next() - meanAngle;
        if (deviation > 180) deviation -= 180;
        if (deviation <= -180) deviation += 180;
        if (deviation > positiveDeviation) positiveDeviation = deviation;
        if (deviation > negativeDeviation) negativeDeviation = deviation;
    }
    return positiveDeviation - negativeDeviation;

平均二乗偏差の場合は、メソッドを使用し (「正規化された」ものではなく、angleを使用)、(-180, 180) の範囲を探し続ける必要があります。

于 2012-12-18T08:50:51.140 に答える
-2

Joni によって受け入れられた回答は、この質問に答えるのに優れた仕事をしますが、Brian Hawkins が指摘したように:

単位に注意してください。書かれている関数は、角度を入力として受け取り、標準偏差をラジアンで返します。

引数と戻り値の両方に度数を使用することで、この問題を修正したバージョンを次に示します。また、可変数の引数を使用できるため、柔軟性も高くなります。

public static double calcStdDevDegrees(double... angles) {
    double sin = 0;
    double cos = 0;
    for (int i = 0; i < angles.length; i++) {
        sin += Math.sin(angles[i] * (Math.PI/180.0));
        cos += Math.cos(angles[i] * (Math.PI/180.0)); 
    }
    sin /= angles.length;
    cos /= angles.length;

    double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));

    return Math.toDegrees(stddev);
}
于 2017-04-30T18:23:43.147 に答える