0

我有一个函数可以估计两个输入数组之间的相关性。

输入由 a 提供dataDict,该类型Dictionary<string, double[]>具有 153 个键,其值为大小为 1500 的双精度数组。

对于每个单独的键,我需要估计它与所有其他键的相关性并将结果存储到double[,]大小为double[dataDict.Count(), dataDict.Count()]

下面的函数准备了两个double[]需要估计相关性的数组。

public double[,] CalculateCorrelation(Dictionary<string, double?[]> dataDict, string corrMethod = "kendall")
        {
            CorrelationLogicModule correlationLogicModule = new CorrelationLogicModule();
            double[,] correlationMatrix = new double[dataDict.Count(), dataDict.Count()];
            for (int i = 0; i < dataDict.Count; i++)
            {                
                for (int j = 0; j < dataDict.Count; j++)
                {
                    var arrayA = dataDict[dataDict.ElementAt(i).Key].Cast<double>().ToArray();
                    var arrayB = dataDict[dataDict.ElementAt(j).Key].Cast<double>().ToArray();
                    correlationMatrix[i, j] = correlationLogicModule.Kendall_Formula(arrayA, arrayB);
                }
            }
            return correlationMatrix;
        }

以下函数(我从这里在互联网上找到)使用“Kendall's”方法查找两个输入数组之间的相关性。

public double Kendall_Formula(double[] Ticker1, double[] Ticker2)
        {
            double NbrConcord, NbrDiscord, S;
            NbrConcord = 0;
            NbrDiscord = 0;
            S = 0;

            for (int i = 0; i < Ticker1.Length - 1; i++)
            {
                for (int j = i + 1; j < Ticker1.Length; j++)
                {
                    //Compute the number of concordant pairs
                    if (((Ticker1[i] < Ticker1[j]) & (Ticker2[i] < Ticker2[j])) | ((Ticker1[i] > Ticker1[j]) & (Ticker2[i] > Ticker2[j])))
                    {
                        NbrConcord++;
                    }
                    //Compute the number of discordant pairs
                    else if (((Ticker1[i] > Ticker1[j]) & (Ticker2[i] < Ticker2[j])) | ((Ticker1[i] < Ticker1[j]) & (Ticker2[i] > Ticker2[j])))
                    {
                        NbrDiscord++;
                    }
                }
            }
            S = NbrConcord - NbrDiscord;
            //Proportion with the total pairs
            return 2 * S / (Ticker1.Length * (Ticker1.Length - 1));
        }

向前推进,需要很长时间来计算所有键的相关性。有没有可能优化性能的方法?

我是 C# 新手,但我已经使用 Python 很长时间了,并且在 Python 中使用“Numpys”和“Pandas”我确信上述操作需要几秒钟的时间来计算。例如,假设我以 pandas 数据框的形式获得上述数据,然后data[[list of columns]].corr('method')将在几秒钟内得出结果。这是因为 pandas 在后台使用了 numpy,这得益于矢量化。我想了解如何从矢量化中受益,以提高上述 C# 代码的性能,以及是否需要考虑其他因素。谢谢!

4

1 回答 1

2

您正在使用dataDict[dataDict.ElementAt(i).Key]以未定义的顺序访问字典值。我不知道这是否是您想要的,但以下代码应该给出相同的结果。

如果您调用dataDict.Values.ToArray();,您将按照与使用foreach迭代时相同的顺序获取字典值。这意味着它将与使用时的顺序相同dataDict[dataDict.ElementAt(i).Key]

因此这段代码应该是等价的,而且应该更快:

public double[,] CalculateCorrelation(Dictionary<string, double?[]> dataDict, string corrMethod = "kendall")
{
    CorrelationLogicModule correlationLogicModule = new CorrelationLogicModule();

    var values = dataDict.Values.Select(array => array.Cast<double>().ToArray()).ToArray();

    double[,] correlationMatrix = new double[dataDict.Count, dataDict.Count];

    for (int i = 0; i < dataDict.Count; i++)
    {
        for (int j = 0; j < dataDict.Count; j++)
        {
            var arrayA = values[i];
            var arrayB = values[j];
            correlationMatrix[i, j] = correlationLogicModule.Kendall_Formula(arrayA, arrayB);
        }
    }
    return correlationMatrix;
}

请注意,.ElementAt()原始代码中的调用是 Linq 扩展,而不是Dictionary<TKey,TValue>. 每次您调用它时,它都会从字典的开头进行迭代 - 它还以未指定的顺序返回项目。从文档中:For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey,TValue> structure representing a value and its key. The order in which the items are returned is undefined.


还:

您应该根据您的条件将按位更改&为逻辑&&。的使用&将阻止编译器应用布尔短路优化,这意味着将执行所有</>比较,即使第一个条件为假。

于 2022-02-11T12:58:48.107 回答