How to find the index of the first element which is greater than a particular value in a matrix for all the columns.

조회 수: 10(최근 30일)
DARSHAN KUMAR BISWAS
DARSHAN KUMAR BISWAS 2022년 6월 10일
댓글: Image Analyst 2022년 6월 11일
Suppose I have a 300 by 300 matrix, containg the values from 0 to 200. For each column, I want to find the position of the first element which is greater than 50. how do I do it. I have tried to write a code but can't do it any further.
no_row=size(c,1);
no_col=size(c,2);
for i=1:no_col
for j=1:no_row
if c(j,i)>=50
end
end
end

채택된 답변

Stephen23
Stephen23 2022년 6월 10일
편집: Stephen23 2022년 6월 10일
N = 5;
M = randi(9,5,7)
M = 5×7
9 3 7 2 8 1 2 1 7 6 4 4 2 9 7 1 6 1 7 6 2 7 3 5 1 1 6 2 6 8 2 9 1 1 7
Method one: CUMSUM and FIND:
X = M>N;
X = X & cumsum(X,1)<2;
[R,~] = find(X)
R = 7×1
1 2 1 5 1 3 2
Method two: FIND and ACCUMARRAY:
[Rx,Cx] = find(M>N);
R = accumarray(Cx,Rx,[],@min)
R = 7×1
1 2 1 5 1 3 2
Method three**: NUM2CELL and CELLFUN (fails if there is no such element in any column):
F = @(v)find(v>N,1,'first');
R = cellfun(F,num2cell(M,1))
R = 1×7
1 2 1 5 1 3 2
  댓글 수: 5
Jan
Jan 2022년 6월 11일
@Stephen23: Of course the methods shown above produce the same result. The dull loop/loop method is 305 times faster than the cellfun approach and does not fail on missing values. I am impressed by this speed, although I actually use Matlab to avoid such low level programming.
I assume, it is much more difficult for a beginner to write a working accumarray appraoch than to implement the nested loop appraoch correctly. So speed and valid code are arguments for the low level method. Unfortunately.

댓글을 달려면 로그인하십시오.

추가 답변(4개)

Image Analyst
Image Analyst 2022년 6월 10일
Try this. It's a loop but only 300 iterations for it's fast, completing in 0.001 seconds:
% Prepare sample image because user forgot to upload the data.
grayImage = 200 * rand(300);
subplot(1, 2, 1);
imshow(grayImage, []);
[rows, columns] = size(grayImage);
% Now scan across columns finding the first row where the value exceeds 200.
tic
topRows = nan(1, columns);
for col = 1 : columns
t = find(grayImage(:, col) > 50, 1, "first");
if ~isempty(t)
topRows(col) = t;
end
end
toc % Takes 0.001 seconds for me
% Plot the location of the top rows.
subplot(1, 2, 2);
plot(topRows, 'r.', 'MarkerSize', 15);
grid on;
xlabel('Column');
ylabel('First row where value > 200')
  댓글 수: 3
Jan
Jan 2022년 6월 11일
Thanks, @Image Analyst, I've found the source of the different speeds: The online interpreter in the forum seems to let the JIT work more powerful in functions than in scripts:
s1 = 300;
s2 = 300;
M = randi([0, 200], s1, s2);
N = 50;
tic
for rep = 1:1e4
R = nan(s2, 1);
for k = 1:s2
v = find(M(:, k) > N, 1);
if ~isempty(v)
R(k) = v;
end
end
end
toc % Code in the main script:
Elapsed time is 3.724234 seconds.
tic;
R = fcn(M, s1, s2, N);
toc % Identical code inside a function:
Elapsed time is 1.392424 seconds.
function R = fcn(M, s1, s2, N)
for rep = 1:1e4
R = nan(s2, 1);
for k = 1:s2
v = find(M(:, k) > N, 1);
if ~isempty(v)
R(k) = v;
end
end
end
end
I'm surprised that this nested loop is 35 times faster (even inside a script):
R = nan(s2, 1);
for k = 1:s2
for kk = 1:s1
if M(kk, k) > N
R(k) = kk;
break;
end
end
end

댓글을 달려면 로그인하십시오.


Mathan
Mathan 2022년 6월 10일
편집: Mathan 2022년 6월 10일
[no_row,no_col] = size(c);
Index_final = [];
for ii = 1:no_col
Index =[];
for jj=1:no_row
if c(jj,ii)>=50
Index = [Index jj]; % Index contains all the elements greater than 50 in that particular column
end
end
if (sum(Index)>0)
Index_final = [Index_final Index(1)]; % Index_final should contain all the required elements in your case.
end
end
  댓글 수: 5

댓글을 달려면 로그인하십시오.


Jan
Jan 2022년 6월 10일
편집: Jan 2022년 6월 10일
s1 = 300;
s2 = 300;
C = randi([0, 200], s1, s2); % Test data
N = 50; % Search
R = nan(s2, 1); % Pre-allocate the output array
for i2 = 1:s2 % Loop over columns
for i1 = 1:s1 % Loop over rows
if C(i1, i2) >= N % Compare the element
R(i2) = i1; % Store in output
break; % Stop "for i1" loop
end
end
end
This is a loop approach equivalent to C or even Basic. Actually Matlab offers more elegant command, see Stephen23's answer. But these "vectorized" methods are slower in modern Matlab versions, because they have to create temporary arrays. The CPU is much faster than the RAM (especially if the data sizes exceed the 1st and 2nd level caches). So this ugly code is much faster than the other suggestions.
This is the case for larger arrays also: I've tested it with 30'000x30'000 matrices.

DARSHAN KUMAR BISWAS
DARSHAN KUMAR BISWAS 2022년 6월 11일
A = [29 33 35 25 33 32 12;3 37 10 22 19 30 9;12 33 19 23 41 11 12;18 23 32 16 27 16 22;42 28 40 26 18 24 16;1 15 5 26 47 12 47;3 38 47 41 44 43 22; 9 10 39 40 28 10 10]
k=zeros(1,7);
for i=1:7
p=A(:,i);
for j=1:8
if p(j)>=40
k(i)=j
plot(7-k)
break
end
end
end
  댓글 수: 2
Image Analyst
Image Analyst 2022년 6월 11일
Yeah, lots of room for improvement in that code.
  1. I'd split A onto separate lines for readability, breaking after the semicolons.
  2. To be more general and robust, I'd get the number of rows and columns of A using size, and use those sizes in the "for" lines and in the call to zeros().
  3. You need "hold on" after plot(), plus you need an (x,y) pair.
  4. No need to use a for loop and break when you can simply use find
See my Answer above to see better coding practice.

댓글을 달려면 로그인하십시오.

제품


릴리스

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by