性能数组乘法Pearson

时间:2016-04-21 18:12:40

标签: c# arrays performance pearson-correlation

我多次计算Pearson correlation(平均用户/项目评分),使用我当前的代码表现非常糟糕:

this.doSomethingElse();

我使用标准Pearson与then的相关性,但这是对标准的修改,并且不可能使用它。有没有办法加快速度?如何在时间复杂度方面进行优化?

3 个答案:

答案 0 :(得分:2)

在MSE上添加一些答案 - 将Pow(x,2)更改为diff*diff绝对是您想要做的事情,您可能还希望避免在最内层循环中进行不必要的边界检查。这可以使用pointers in C#完成。

可以这样做:

    public unsafe double ComputeCorrelation(double[] x, double[] y, double[] meanX, double[] meanY)
    {
        if (x.Length != y.Length)
            throw new ArgumentException("values must be the same length");

        double sumNum = 0;
        double sumDenom = 0;
        double denomX = 0;
        double denomY = 0;
        double diffX;
        double diffY;

        int len = x.Length;

        fixed (double* xptr = &x[0], yptr = &y[0], meanXptr = &meanX[0], meanYptr = &meanY[0])
        {
            for (int a = 0; a < len; a++)
            {
                diffX = (xptr[a] - meanXptr[a]);
                diffY = (yptr[a] - meanYptr[a]);
                sumNum += diffX * diffY;
                denomX += diffX * diffX;
                denomY += diffY * diffY;
            }
        }

        var sqrtDenomX = Math.Sqrt(denomX);
        var sqrtDenomY = Math.Sqrt(denomY);

        if (sqrtDenomX == 0 || sqrtDenomY == 0) return 0;

        sumDenom = sqrtDenomX * sqrtDenomY;

        var correlation = sumNum / sumDenom;

        return correlation;
    }

答案 1 :(得分:1)

解决性能问题的最佳方法是尽可能避免计算尽可能多的相关性。如果您将相关性用作另一个计算的一部分,则可以使用数学来消除对其中某些计算的需要。

您还应该考虑是否能够使用Pearson相关的平方而不是Pearson相关本身。这样,您就可以将通话保存到Math.Sqrt(),这通常非常昂贵。

如果你确实需要取平方根,你应该再次使用sqrtDenomXsqrtDenomY,而不是重新计算平方根。

答案 2 :(得分:1)

我在代码中看到的唯一可能的优化是在以下代码中,如果您仍在寻找更好的性能,那么您可能需要使用SIMD vectorization。它允许您使用CPU的全部计算能力

public double ComputeCorrelation(double[] x, double[] y, double[] meanX, double[] meanY)
    {
        if (x.Length != y.Length)
            throw new ArgumentException("values must be the same length");

        double sumNum = 0;
        double sumDenom = 0;
        double denomX = 0;
        double denomY = 0;
        double diffX;
        double diffY;

        for (int a = 0; a < x.Length; a++)
        {
            diffX = (x[a] - meanX[a]);
            diffY = (y[a] - meanY[a]);
            sumNum += diffX * diffY;
            denomX += diffX * diffX;
            denomY += diffY * diffY;
        }

        var sqrtDenomX = Math.Sqrt(denomX);
        var sqrtDenomY = Math.Sqrt(denomY);

        if (sqrtDenomX == 0 || sqrtDenomY == 0) return 0;

        sumDenom = sqrtDenomX * sqrtDenomY;

        var correlation = sumNum / sumDenom;

        return correlation;
    }