Vectorizable FIND function with if statement MATLAB

寵の児 提交于 2020-01-24 21:16:53

问题


I have a matrix u, I want to go across all rows and all columns and do the following. If the element is non zero, I return the value of the row index. If the element is zero, find the row index the next non zero element after this element. I can do this easily using two for loops with a find function. But I need to do this many many times (not because of the size of the matrix but because this is called many times). How can I do it faster?

here is the for loop code:

     for w=scenario_size:-1:1
            for t=1:time_size
                l = u(t,w) ;
                if l~=0
                    tprime = t ;
                else
                    tprime = t+ find(u(t:end,w),1,'first') -1 ;
                end
                i(t,w)       = tprime ;
                boo(t,w)     = number(tprime,w)/u(tprime,w) ;
            end
end

Example if one column is [0,0,5,1,0,3], the i is [3,3,3,4,6,6]. The last element of any column of u is always non-zero (I forced this by artificially adding a row of ones at the end).

Then boo is the corresponding entry to tprime for some matrix number divided by the corresponding u (which is non zero by construction).


回答1:


You can solve this using find, cummin, and some logical indexing. Starting with this example case:

>> u = randi([0 1], 10);
>> u(end, :) = 1

u =

     0     0     0     0     1     0     1     0     1     1
     1     0     1     1     1     0     0     0     0     1
     0     0     0     0     0     1     0     1     1     0
     1     1     1     0     1     1     0     0     0     0
     0     0     1     0     0     0     0     0     1     0
     1     1     1     0     0     0     0     0     0     0
     0     1     0     1     0     0     1     1     0     1
     1     1     0     1     0     1     1     1     1     1
     1     0     0     1     0     0     1     1     1     1
     1     1     1     1     1     1     1     1     1     1

The following will do what you want:

i = nan(size(u));  % Start with all nan values
[r, ~] = find(u);  % Get row indices of non-zero values
i(u ~= 0) = r;     % Place row indices in locations of non-zero values
i = cummin(i, 1, 'reverse');  % Column-wise cumulative minimum, starting from bottom

And the result:

i =

     2     4     2     2     1     3     1     3     1     1
     2     4     2     2     2     3     7     3     3     2
     4     4     4     7     4     3     7     3     3     7
     4     4     4     7     4     4     7     7     5     7
     6     6     5     7    10     8     7     7     5     7
     6     6     6     7    10     8     7     7     8     7
     8     7    10     7    10     8     7     7     8     7
     8     8    10     8    10     8     8     8     8     8
     9    10    10     9    10    10     9     9     9     9
    10    10    10    10    10    10    10    10    10    10

And you can then calculate your matrix boo by converting i to a linear index:

index = i+time_size.*repmat(0:(scenario_size-1), time_size, 1);  % Create linear index
boo = number(index)./u(index);

Alternatively, you can compute i as a linear index from the start:

i = nan(size(u));  % Start with all nan values
index = find(u);   % Get linear indices of non-zero values
i(index) = index;  % Place linear indices in locations of non-zero values
i = cummin(i, 1, 'reverse');  % Column-wise cumulative minimum, starting from bottom
boo = number(i)./u(i);



回答2:


@gnovice answer is good, just to give an alternative to find function

  • First the u matrix
    >> u = randi([0 1], 10);
    u(end, :) = 1;
    >> u

    u =

         0     0     0     0     0     1     1     0     0     0
         0     1     1     1     0     1     0     1     1     1
         1     1     1     0     1     0     0     1     1     0
         1     1     1     1     1     0     1     1     0     1
         1     1     0     1     1     1     1     0     0     0
         0     0     1     0     1     1     1     0     0     1
         0     1     0     0     1     1     0     0     0     1
         0     1     0     1     1     1     0     1     1     0
         0     0     0     1     0     1     1     1     1     1
         1     1     1     1     1     1     1     1     1     1
  • Then the non-zeros row indices can be computed as follow
    >> t = 1:10*10;% All elements indices
    r = t(u ~= 0); % All non-zeros elements indices 
    >> r

    r =

      Columns 1 through 18

         3     4     5    10    12    13    14    15    17    18    20    22    23    24    26    30    32    34

      Columns 19 through 36

        35    38    39    40    43    44    45    46    47    48    50    51    52    55    56    57    58    59

      Columns 37 through 54

        60    61    64    65    66    69    70    72    73    74    78    79    80    82    83    88    89    90

      Columns 55 through 60

        92    94    96    97    99   100


来源:https://stackoverflow.com/questions/56363677/vectorizable-find-function-with-if-statement-matlab

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!