【问题标题】:Calculate a "running" maximum of a vector计算向量的“运行”最大值
【发布时间】:2014-12-03 13:00:44
【问题描述】:

我有以下矩阵来跟踪数据范围的起点和终点(第一列代表"starts",第二列代表"ends"):

myMatrix = [
    162   199; %// this represents the range 162:199
    166   199; %// this represents the range 166:199
    180   187; %// and so on...
    314   326;
    323   326;
    397   399;
    419   420;
    433   436;
    576   757;
    579   630;
    634   757;
    663   757;
    668   757;
    676   714;
    722   757;
    746   757;
    799   806;
    951   953;
    1271  1272
];

我需要消除矩阵中较大范围内包含的所有范围(即行)。例如,[166:199][180:187] 范围包含在[162:199] 范围内,因此需要删除第 2 行和第 3 行。

我想到的解决方案是在第二列上计算一种“正在运行”max,与该列的后续值进行比较以确定是否需要删除它们。我使用for 循环实现了这一点,如下所示:

currentMax = myMatrix(1,2); %//set first value as the maximum
[sizeOfMatrix,~] = size(myMatrix); %//determine the number of rows
rowsToRemove = false(sizeOfMatrix,1); %//pre-allocate final vector of logicals
for m=2:sizeOfMatrix
    if myMatrix(m,2) > currentMax %//if new max is reached, update currentMax...
        currentMax = myMatrix(m,2);
    else
        rowsToRemove(m) = true; %//... else mark that row for removal
    end
end
myMatrix(rowsToRemove,:) = [];

这会正确删除myMatrix 中的“冗余”范围并生成以下矩阵:

myMatrix =
         162         199
         314         326
         397         399
         419         420
         433         436
         576         757
         799         806
         951         953
        1271        1272

关于问题:

1) 似乎必须有一种比for 循环更好的方法来计算“正在运行”的max。我查看了accumarrayfilter,但无法找到使用这些功能的方法。是否有跳过for 循环的潜在替代方案(某种更有效的矢量化代码)?

2) 是否有一种完全不同(即更有效)的方法来完成删除myMatrix 中较大范围内包含的所有范围的最终目标?我不知道我是不是想太多了……

【问题讨论】:

  • 这个矩阵有多大?如果不是太大,我看不出成对比较有什么问题
  • myMatrix 可能不会超过 100 行左右。问题是我将需要运行大量这些矩阵。
  • 有一个线程 here 关于实现一个累积最大函数,我相信这是你第一个问题的答案。我以类似的方式使用了该算法(参见here),发现它的性能很好。
  • 如果第一列没有排序怎么办?您的循环解决方案似乎不适用于这种情况。或者您是否假设您的实际数据集不会出现这种情况?

标签: matlab matrix vectorization


【解决方案1】:

方法#1

bsxfun 基于蛮力方法 -

myMatrix(sum(bsxfun(@ge,myMatrix(:,1),myMatrix(:,1)') & ...
    bsxfun(@le,myMatrix(:,2),myMatrix(:,2)'),2)<=1,:)

对提议的解决方案的解释很少:

  1. 比较所有 starts 索引的“包含性”,类似地比较 ends 索引。请注意,“包含”标准必须适用于这两个中的任何一个:

    • 大于或等于 starts 且小于或等于 ends
    • 小于或等于starts,大于或等于ends

    我只是碰巧选择了第一个选项。

  2. 查看哪些行至少满足一个“包含性”并删除这些行以获得所需的结果。


方法#2

如果您可以接受根据第一列对行进行排序的输出,并且如果 local max's 的数量较少,您可以尝试这种替代方法 -

myMatrix_sorted = sortrows(myMatrix,1);
col2 = myMatrix_sorted(:,2);
max_idx = 1:numel(col2);
while 1
    col2_selected = col2(max_idx);
    N = numel(col2_selected);
    labels = cumsum([true ; diff(col2_selected)>0]);
    idx1 = accumarray(labels, 1:N ,[], @(x) findmax(x,col2_selected));
    if numel(idx1)==N
        break;
    end
    max_idx = max_idx(idx1);
end
out = myMatrix_sorted(max_idx,:); %// desired output

相关功能码-

function ix = findmax(indx, s)
[~,ix] = max(s(indx));
ix = indx(ix);
return;

【讨论】:

  • +1 这也是我的方法。我的意思是方法 1,当然 :-)
  • @LuisMendo 哈哈,我以为那是方法#2! :) 那么关于方法#2,我不喜欢在那里使用anonymous function,不要相信它的性能。
  • 方法 2?不!那个“不循环,是的,bsxfun”在哪里? :-P
  • @LuisMendo 好吧.. 有时我们也需要打破自己的规则! ;)
【解决方案2】:

我最终使用以下解决“最大运行”问题(但相对于其他解决方案的效率没有评论):

function x = cummax(x)
% Cumulative maximum along dimension 1
% Adapted from http://www.mathworks.com/matlabcentral/newsreader/view_thread/126657
% Is recursive, but magically so, such that the number of recursions is proportional to log(n).

n = size(x, 1);
%fprintf('%d\n', n)
if n == 2
    x(2, :) = max(x);
elseif n  % had to add this condition relative to the web version, otherwise it would recurse infinitely with n=0
    x(2:2:n, :) = cummax(max(x(1:2:n-1, :), x(2:2:n,   :)));
    x(3:2:n, :) =        max(x(3:2:n,   :), x(2:2:n-1, :));
end

【讨论】:

    猜你喜欢
    • 2014-09-13
    • 2023-04-07
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 1970-01-01
    • 2015-03-18
    相关资源
    最近更新 更多