【问题标题】:How to reduce the time complexity of my O(N^2) C-index function?如何降低我的 O(N^2) C-index 函数的时间复杂度?
【发布时间】:2015-05-05 09:31:08
【问题描述】:

我有以下函数(在 Matlab 中),它将计算给定一组预测和观察值的一致性指数:

function civalue = CI(predval)
% FUNCTION civalue = CI(predval)
%
% DESCRIPTION: 
% - This function will calculate the concordance index. Not suitable for
% big vectors. O(n^2) time function. 
%
% INPUTS: 
% 'predval' a n-by-2 matrix, where the first column consists of the
% prediction values and the second column the actual label values. 
%
% OUTPUT: 
% 'civalue' the CI-value.

N = 0;
hSum = 0;

for i = 1:size(predval, 1)

    yi_pred = predval(i, 1);
    yi_val = predval(i, 2);
    for j = i+1:size(predval, 1)
        yj_pred = predval(j, 1);
        yj_val = predval(j, 2);
        if yi_val ~= yj_val
            N = N + 1;
            if  (yi_pred < yj_pred && yi_val < yj_val) || (yi_pred > yj_pred && yi_val > yj_val) % Order correct
                hSum = hSum + 1;
            elseif (yi_pred < yj_pred && yi_val > yj_val) || (yi_pred > yj_pred && yi_val < yj_val) % Order opposite 
                hSum = hSum + 0;
            elseif yi_pred == yj_pred % Random
                hSum = hSum + 0.5;
            end
        end
    end

end

civalue = hSum / N;

我的函数的时间复杂度为 O(N^2)。代码的想法是在数据点之间进行成对比较。有什么想法可以降低代码的时间复杂度吗?

CI 值或 C 指数背后的理念是衡量预测模型将数据点排列成正确顺序的能力。你给这个函数的是一组观测值 X 和它们对应的预测 Y。这个函数会对不同观测值的数据点进行排名比较,因为它们显然是有排名的。

例如,假设您对某个变量有两个观察值,例如股价:P1 = 5$, P2 = 7$

现在我们创建一个模型来尝试预测股票价格。假设我们建立了我们的模型并测试了它预测股票价格的能力,并且对于两个数据点 P1、P2,它预测了 Y1 = 5.5$ 和 Y2 = 8$ 的值。

现在您可以看到模型的 ORDER 正确,P1

感谢大家的帮助!如果您需要更多信息等,请告诉我:)

下面是我自己的实现和 Martin 的实现对比:

【问题讨论】:

  • 你能定义你到底要计算什么吗,我不确定我是否熟悉 CI 值术语
  • @amit 我为 C-index 添加了一些解释,它有帮助吗?
  • predval 的典型数据大小是多少?
  • @Divakar 嗨,它可以有 n×2 大小的矩阵,其中 n 是任意的。在我的应用程序中,我有大小为 50×2、12000×2、1100×2 等的矩阵。但我们也有 1,000,000×2 矩阵的应用程序。我想降低时间复杂度的主要原因是因为我将这个函数调用了 M 次,即使整个一次迭代计算需要 1 秒,如果我有很多实验(大 M)并且我必须等待,它仍然非常慢几个小时......
  • 如果有,您可以在开始时执行此操作 - predval = gpuArray(predval);,然后使用我的代码。否则,Martin 在这里的回答对我来说看起来很快,可以被接受。

标签: performance algorithm matlab matrix time


【解决方案1】:

您可以通过矢量化内部循环来显着提高运行时间。下面的代码可以进一步优化(以易读性为代价)。在我的机器上,使用随机输入,代码运行速度提高了大约 50 倍,并产生了相同的结果。 (随机输入可能是一个糟糕的测试用例,因为== 分支永远不会执行)

N = 0;
hSum = 0;
for i = 1:size(predval, 1)

    yi_pred = predval(i, 1);
    yi_val = predval(i, 2);
    yj_pred = predval(i+1:end,1);
    yj_val = predval(i+1:end,2);
    idxs = yi_val ~= yj_val;
    N = N + sum(idxs);

    yj_pred = yj_pred(idxs); % redefined to make the next lines prettier
    yj_val = yj_val(idxs); 
    hSum = hSum + sum((yi_pred < yj_pred & yi_val < yj_val) | ...
        (yi_pred > yj_pred & yi_val > yj_val)); % Order correct
    hSum = hSum + 0.5*sum(yi_pred == yj_pred); % Order random
end

不过,函数的复杂度仍然是 O(n^2)。

【讨论】:

  • 这确实很快!干得好。
  • 感谢您的帮助! =)
  • 嗨@MartinJ.H。我想知道我做错了什么,因为当我测试这个新代码时,我得到的结果比我用旧代码得到的结果要慢?....我制作了一个随机的 20000×2 矩阵并将其作为我自己的输入你的代码和我的更快? :O 我的代码在我的电脑上用了 4.9 秒,你的用了 7.9 秒....
  • 我发布了您和我的代码的比较...为什么我的代码更好?....您是如何将速度提高 50 倍的? =) 谢谢你的帮助!
  • 有趣!我没有将代码保存为函数,而是在“单元模式”下将其作为脚本的一部分执行。不知何故,这对您的实施产生了巨大的影响,而对我的影响却很小。当我将两者都保存为函数时,您的实现也会更快。我想在后台有一些函数的预编译。原则上,最好在 Matlab 中对代码进行矢量化处理,即放弃 for 循环。这是我看到的第一个相反的例子!
【解决方案2】:

假设您的最终目标是提高运行时性能,并且如果您有足够好的内存来运行矢量化方法,那么这可能就是其中之一 -

%// Column arrays
c1 = predval(:,1);
c2 = predval(:,2);

%// Get logical arrays of IF conditional statements in the original code
start_cond = bsxfun(@ne,c2,c2.')               %//'# starting condition

%// Rest of the three IF conditionals
case1 = bsxfun(@lt,c1,c1.') & bsxfun(@lt,c2,c2.') | ...
    bsxfun(@gt,c1,c1.') & bsxfun(@gt,c2,c2.')  %//'
case2 = bsxfun(@lt,c1,c1.') & bsxfun(@gt,c2,c2.') | ...
    bsxfun(@gt,c1,c1.') & bsxfun(@lt,c2,c2.')  %//'
case3 = bsxfun(@eq,c1,c1.')                    %//'

%// Get the counts for different cases and finally get the output sum
w1 = start_cond & case1
w2 = start_cond & ~case1 & ~case2 & case3
hSum = sum(w1(:))./2 + sum(w2(:))./4

【讨论】:

  • 嗨@Divakar 你是否也使用 Martin J.H. 的代码获得了更好的结果?在我的电脑中,由于某种原因,我的运行时间变差了……我在上面发布了比较……知道为什么我的速度更快吗?
  • @jjepsuomi 啊!我之前没有与您的基准进行对比。但就像我现在所做的那样,你原来的方法似乎是最快的!好吧,我刚刚针对在 NVIDIA GTX 750 Ti 上运行的代码的 GPU 版本进行了测试,它比您原来的版本要快得多,所以如果您有一些 NVIDIA GPU,它可以帮助您,否则请坚持使用您原来的版本。
猜你喜欢
  • 2022-10-08
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多