首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >性能阵列乘法Pearson

性能阵列乘法Pearson
EN

Stack Overflow用户
提问于 2016-04-21 18:12:39
回答 3查看 89关注 0票数 2

我多次计算Pearson相关 (平均用户/项评等),使用我当前的代码性能非常糟糕:

代码语言:javascript
运行
复制
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;

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

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

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

            sumDenom = Math.Sqrt(denomX) * Math.Sqrt(denomY);

            var correlation = sumNum / sumDenom;

            return correlation;
        }

我正在使用标准皮尔逊相关性与MathNet.Numerics,但这是对标准的修改,它是不可能使用它。有办法加快速度吗?如何对时间复杂性进行优化?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-23 16:32:44

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

可以这样做:

代码语言:javascript
运行
复制
    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;
    }
票数 2
EN

Stack Overflow用户

发布于 2016-04-21 18:25:37

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

您还应该考虑是否能够使用Pearson相关的平方,而不是Pearson相关性本身。这样,您就可以节省对Math.Sqrt()的调用,这通常是相当昂贵的。

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

票数 1
EN

Stack Overflow用户

发布于 2016-04-21 21:23:38

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

代码语言:javascript
运行
复制
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;
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36777383

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档