如何有效地计算对数回报

米克

我有一个多维数组double[,] results,其中每一列代表特定项目(例如汽车,房屋...)的价格时间序列。我想将每个时间序列的对数回报计算为Log(price_t / price_t1)其中t> t1。因此,我将为的每一列生成一个新的对数返回时间序列double[,] results如何在C#中以有效的方式完成此操作?数据量很大,我正在尝试以下解决方案:

for(int col = 1; col <= C; col++)
{
     for(int row = 1; row <= R; row++)
     {
         ret = Math.Log(results[row+1;col]/ results[row;col])
     }
}

其中C和R是中的列数和行数double[,] results这种解决方案运行速度很慢,效率似乎很低。任何建议如何更快地执行类似的计算?

我看到在像MATLAB这样的语言中,人们可以对代码进行矢量化处理,然后将原始矩阵除以另一矩阵,而后者又被一个元素滞后。然后取除法得到的整个矩阵的对数。它在C#中可行吗?

马丁·利弗塞奇

如果您的计算机具有多个内核,则可以轻松提高计算速度。为了自己尝试一下,我首先创建了以下功能:

Double[,] ComputeLogReturns(Double[,] data) {
  var rows = data.GetLength(0);
  var columns = data.GetLength(1);
  var result = new Double[rows - 1, columns];
  for (var row = 0; row < rows - 1; row += 1)
    for (var column = 0; column < columns; column += 1)
      result[row, column] = Math.Log(data[row + 1, column]/data[row, column]);
  return result;
}

我使用1,000 x 1,000值的输入数组对该功能进行了基准测试。在我的计算机上,执行100次呼叫的时间约为3秒。

因为循环的主体可以并行执行,所以我重写了要使用的函数Parallel.For

Double[,] ComputeLogReturnsParallel(Double[,] data) {
  var rows = data.GetLength(0);
  var columns = data.GetLength(1);
  var result = new Double[rows - 1, columns];
  Parallel.For(0, rows - 1, row => {
    for (var column = 0; column < columns; column += 1)
      result[row, column] = Math.Log(data[row + 1, column]/data[row, column]);
  });
  return result;
}

在具有4个核心(8个逻辑核心)的计算机上,执行100个调用大约需要0.9秒。这快了3倍多,表明只有物理核而不是逻辑核才能够计算对数。

现代x86 CPU具有称为SSE的特殊指令,使您可以向量化某些计算。我希望MATLAB使用这些指令,并且可以解释为什么与您自己的C#代码相比,您在MATLAB中的性能要好得多。

为了测试SSE,我尝试了Yeppp!绑定到C#。该库可作为预发行版本在NuGet上使用,并具有对数函数。SSE指令仅适用于一维数组,因此我重写了基线函数:

Double[] ComputeLogReturns(Double[] data, Int32 rows, Int32 columns) {
  var result = new Double[(rows - 1)*columns];
  for (var row = 0; row < rows - 1; row += 1)
    for (var column = 0; column < columns; column += 1)
      result[row*columns + column] = Math.Log(data[(row + 1)*columns + column]/data[row*columns + column]);
  return result;
}

在相同的输入和100次迭代的情况下,执行时间现在似乎少于3秒,这表明一维数组可能会稍微提高性能(但从逻辑上讲,除非是影响执行时间的额外参数检查,否则它不应这样做)。

使用Yeppp!该函数变为:

Double[] ComputeLogReturnsSse(Double[] data, Int32 rows, Int32 columns) {
  var quotient = new Double[(rows - 1)*columns];
  for (var row = 0; row < rows - 1; row += 1)
    for (var column = 0; column < columns; column += 1)
      quotient[row*columns + column] = data[(row + 1)*columns + column]/data[row*columns + column];
  var result = new Double[(rows - 1)*columns];
  Yeppp.Math.Log_V64f_V64f(quotient, 0, result, 0, quotient.Length);
  return result;
}

我找不到使用Yeppp执行矢量化除法的函数!因此该划分是使用“常规”划分执行的。但是,我仍然希望对数是最昂贵的运算。最初的性能令人恐惧,迭代100次,耗时17秒,但后来我注意到Yeppp中存在问题!关于以32位进程运行时的不良性能。切换到64位可显着提高性能,从而导致大约1.3秒的执行时间。摆脱函数内部的两个数组分配(重复执行100次),将执行时间降低到大约0.7秒,这比并行实现要快。使用Parallel.For进行乘法运算可以将执行时间降低到0.4秒左右。如果是耶普!有一种执行除法的方法(SSE拥有这种方法),您可能会得到更短的执行时间,也许会导致速度提高十倍。

根据我对SSE的实验,您应该能够实现相当大的性能改进。但是,如果这很重要,您可能应该注意精度。与.NET实现相比,SSE日志功能提供的结果可能略有不同。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何有效地计算MySQL中的序列中断/漏洞?

来自分类Dev

如何有效地计算数据

来自分类Dev

有效地计算体素数据的梯度

来自分类Dev

如何有效地计算大量数字的均值和标准差?

来自分类Dev

如何通过ID有效地计算地图中的difftime

来自分类Dev

numpy有效地计算多项式

来自分类Dev

如何使用Matlab有效地计算矩阵项

来自分类Dev

如何快速有效地计算平均值(移动平均值)?

来自分类Dev

如何在numpy中有效地计算高斯核矩阵?

来自分类Dev

有效地计算双积分

来自分类Dev

有效地计算(a-K)/(a + K)

来自分类Dev

如何有效地计算图像浏览量(负载)?

来自分类Dev

应用某些函数后如何有效地计算集合的最大值

来自分类Dev

如何有效地计算跑步中位数

来自分类Dev

如何在python中有效地计算(稀疏)位矩阵的矩阵乘积

来自分类Dev

如何更有效地计算滚动协方差

来自分类Dev

如何有效地计算运行最大值的熊猫数据帧?

来自分类Dev

有效地计算邻接矩阵

来自分类Dev

熊猫-有效地计算组合算术

来自分类Dev

如何有效地使用OWLAPI计算脱节?

来自分类Dev

如何有效地计算怪异数字

来自分类Dev

如何有效地计算多个时间序列的欧几里得距离矩阵

来自分类Dev

如何有效地计算顶部排列

来自分类Dev

如何更有效地计算滚动比

来自分类Dev

如何在 Matlab 中有效地计算单个有限差分?

来自分类Dev

SQL:有效地计算花费的时间

来自分类Dev

有效地计算总和矩阵

来自分类Dev

如何有效地语法

来自分类Dev

如何在matlab中有效地对数据进行bin