4

我正在尝试实现一种将线拟合到 2D 中的一组点的方法。我编写了以下代码,它从两个数组(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 有时大于一,恕我直言,如果一切正常,则永远不会发生这种情况。

有人在我的实施中看到任何错误吗?

- 编辑 -

这是更正的代码,遵循 CRD 的提示。我用它来提取两个步骤之间水平面上采样的用户加速度的方向向量,以获得步骤方向。

这对我有用:

- (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

Put in some known data you can check by hand, e.g. {1,1}, {2,2}, {3,3}. Are the averages correct? If so move on to the sums, etc. The error will reveal itself.

On the code itself you can make it clearer, and incidentally more efficient, by dropping the calls to @"avg.doubleValue" and producing all your sums in a single loop:

// 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 回答