4

2Dの点のセットに線を合わせるメソッドを実装しようとしています。2つの配列(X、Y座標)からデータを読み取り、最小二乗法で最適な直線のパラメーターを計算する次のコードを作成しました。私はここで与えられた式を使用しました: mathworld.wolfram

- (void) linearRegressionOfUserAcceleration 
{
     double avgX = [[_accelBufferX valueForKeyPath:@"@avg.doubleValue"] doubleValue];
     double avgY = [[_accelBufferY valueForKeyPath:@"@avg.doubleValue"] doubleValue];
     int n = _accelBufferX.count;

     double ssX, ssY, ssXY;
     ssX = ssY = ssXY = 0;
     int i;

     // Sum of squares X, Y & X*Y
     for (i = 0; i < n; i++)
     {
         ssX += pow([[_accelBufferX objectAtIndex:i] doubleValue],2);
         ssY += pow([[_accelBufferY objectAtIndex:i] doubleValue],2);
         ssXY += [[_accelBufferX objectAtIndex:i] doubleValue] * [[_accelBufferY objectAtIndex:i] doubleValue];
     }

     ssX = ssX - n * pow(avgX,2);
     ssY = ssY - n * pow(avgY,2);
     ssXY = ssXY - n * avgX * avgY;

     // Best fit of line y_i = a + b * x_i 
     b = ssXY / ssX;
     a = avgY - b * avgX;

     // Correlationcoefficent gives the quality of the estimate: 1 = perfect to 0 = no fit
     corCoeff = pow(ssXY,2) / ssX * ssY;

     NSLog(@"n: %d, a: %f --- b: %f --- cor: %f --- avgX: %f --- avgY: %f --- ssX: %f - ssY: %f - ssXY: %f", n, a, b, corCoeff, avgX, avgY, ssX, ssY, ssXY);
}

次のような出力が得られます。

  n: 15, a: -0.095204 --- b: 0.929245 --- cor: 3.567163   --- avgX: -0.017827 -- avgY: -0.111770 --- ssX: 2.176048 - ssY: 1.898429 - ssXY: 2.022081

結果の行はデータにまったく適合しません。corelationCoefficientが1より大きい場合もありますが、すべてが正しく機能していれば、IMHOは発生しないはずです。

誰かが私の実装にエラーを見つけましたか?

- 編集 -

これは、CRDからのヒントに従って修正されたコードです。これを使用して、2つのステップ間の水平面でサンプリングされたuserAccelerationの方向ベクトルを抽出し、ステップの方向を取得しました。

これは私のために働いた:

- (void) linearRegressionOfUserAcceleration
{
    NSUInteger n = _accelBufferX.count;
    double ax, ay, sX, sY, ssX, ssY, ssXY, avgX, avgY;

    // Sum of squares X, Y & X*Y
    for (NSUInteger i = 0; i < n; i++)
    {
        @synchronized(self) {
            ax = [[_accelBufferX objectAtIndex:i] doubleValue];
            ay = [[_accelBufferY objectAtIndex:i] doubleValue];
        }
        sX += ax;
        sY += ay;
        ssX += ax * ax;
        ssY += ay * ay;
        ssXY += ax * ay;
    }

    avgX = sX / n;
    avgY = sY / n;
    radius = hypot(avgX, avgY);
    ssX = ssX - n * (avgX * avgX);
    ssY = ssY - n * (avgY * avgY);
    ssXY = ssXY - n * avgX * avgY;

    // Best fit of line y_i = a + b * x_i
    b = ssXY / ssX;
    a = (avgY - b * avgX);
    theta = atan2(1, b);


    // Correlationcoefficent gives the quality of the estimate: 1 = perfect to 0 = no fit
    corCoeff = (ssXY * ssXY) / (ssX * ssY);

    NSLog(@"n: %d, a: %f --- b: %f --- cor: %f   --- avgX: %f -- avgY: %f --- ssX: %f - ssY: %f - ssXY: %f", n, a, b, corCoeff, avgX, avgY, ssX, ssY, ssXY);
}
4

1 に答える 1

3

手作業で確認できる既知のデータ({1,1}、{2,2}、{3,3}など)を入力します。平均は正しいですか?その場合は、合計などに進みます。エラーが明らかになります。

コード自体では、@ "avg.doubleValue"への呼び出しをドロップし、すべての合計を1つのループで生成することにより、コードをより明確にし、偶然により効率的にすることができます。

// Sum of X, Y, X^2, Y^2 & X*Y
for (NSUInteger i = 0; i < n; i++)
{
   double x = [[_accelBufferX objectAtIndex:i] doubleValue];
   double y = [[_accelBufferY objectAtIndex:i] doubleValue];
   sX += x;
   sY += y;
   ssX += x * x;
   ssY += y * y;
   ssXY += x * y;
}
于 2012-06-02T20:03:32.780 に答える