计算矩阵中每个值实例之间的行数

时间:2014-10-21 22:13:58

标签: performance matlab matrix

假设以下矩阵:

myMatrix = [
1   0   1
1   0   0
1   1   1
1   1   1
0   1   1
0   0   0
0   0   0
0   1   0
1   0   0
0   0   0
0   0   0
0   0   1
0   0   1
0   0   1    
];

鉴于上述情况(并独立处理每一列),我正在尝试创建一个矩阵,该矩阵将包含自1的最后一个值“已显示”以来的行数。例如,在第一列中,前四个值将变为0,因为每个行之间有0行,而前一个值1

第5行将变为1,第6行= 2,第7行= 3,第8行= 4。由于第9行包含1,因此它将变为0,并且计数将再次从第10行开始。最终矩阵应如下所示:

FinalMatrix = [
0   1   0
0   2   1
0   0   0
0   0   0
1   0   0
2   1   1
3   2   2
4   0   3
0   1   4
1   2   5
2   3   6
3   4   0
4   5   0
5   6   0     
];

完成这样的事情的好方法是什么?

编辑:我目前正在使用以下代码:

[numRow,numCol] = size(myMatrix);
oneColumn = 1:numRow;
FinalMatrix = repmat(oneColumn',1,numCol);
toSubtract = zeros(numRow,numCol);
for m=1:numCol
    rowsWithOnes = find(myMatrix(:,m));
    for mm=1:length(rowsWithOnes);
        toSubtract(rowsWithOnes(mm):end,m) = rowsWithOnes(mm);
    end
end
FinalMatrix = FinalMatrix - toSubtract;

比在许多试验和数据集(大小约为1500 x 2500)上发布的bsxfun解决方案运行速度快约5倍。上面的代码可以优化吗?

2 个答案:

答案 0 :(得分:3)

对于单个列,您可以执行此操作:

col = 1; %// desired column
vals = bsxfun(@minus, 1:size(myMatrix,1), find(myMatrix(:,col)));
vals(vals<0) = inf;
result = min(vals, [], 1).';

第一栏的结果:

result =
     0
     0
     0
     0
     1
     2
     3
     4
     0
     1
     2
     3
     4
     5

答案 1 :(得分:1)

基于{p> find + diff + cumsum的方法 -

offset_array = zeros(size(myMatrix));
for k1 = 1:size(myMatrix,2)
    a = myMatrix(:,k1);
    widths = diff(find(diff([1 ; a])~=0));
    idx = find(diff(a)==1)+1;
    offset_array(idx(idx<=numel(a)),k1) = widths(1:2:end);
end
FinalMatrix1 = cumsum(double(myMatrix==0) - offset_array);

基准

此处列出了将上述方法与问题中的方法进行比较的基准代码 -

clear all
myMatrix = round(rand(1500,2500)); %// create random input array
for k = 1:50000
    tic(); elapsed = toc(); %// Warm up tic/toc
end

disp('------------- With FIND+DIFF+CUMSUM based approach') %//'#
tic
offset_array = zeros(size(myMatrix));
for k1 = 1:size(myMatrix,2)
    a = myMatrix(:,k1);
    widths = diff(find(diff([1 ; a])~=0));
    idx = find(diff(a)==1)+1;
    offset_array(idx(idx<=numel(a)),k1) = widths(1:2:end);
end
FinalMatrix1 = cumsum(double(myMatrix==0) - offset_array);
toc
clear FinalMatrix1 offset_array idx widths a

disp('------------- With original approach') %//'#
tic
[numRow,numCol] = size(myMatrix);
oneColumn = 1:numRow;
FinalMatrix = repmat(oneColumn',1,numCol); %//'#
toSubtract = zeros(numRow,numCol);
for m=1:numCol
    rowsWithOnes = find(myMatrix(:,m));
    for mm=1:length(rowsWithOnes);
        toSubtract(rowsWithOnes(mm):end,m) = rowsWithOnes(mm);
    end
end
FinalMatrix = FinalMatrix - toSubtract;
toc

我得到的结果是 -

------------- With FIND+DIFF+CUMSUM based approach
Elapsed time is 0.311115 seconds.
------------- With original approach
Elapsed time is 7.587798 seconds.