I have a 3d matrix of average global temperatures (0.5 degree lat/long) for 42 years (42×720×1440). For a given year (say year 42) I want to create a new matrix (720 × 1440) that ranks each lat/long pair based on the other 41 years. So if a lat/long pair is warmest, it will have a rank value of 1. If it's coolest, it will have a rank value of 42. The resulting matrix will be 720 x 1440 matrix of values ranked from 1 to 42 based on the original matrix. Is there a simple way to take a given year from the original matrix to do this without looping?

 Akzeptierte Antwort

Matt J
Matt J am 8 Mai 2024
Bearbeitet: Matt J am 8 Mai 2024

0 Stimmen

Also how can NaN values be ignored in this solution?
Here's a revised method (loop-free) that also handles NaNs. As before, ranks(:,:,i) represents the rankings for year i.
T = randi(100,3,2,5); T(1)=nan; % random temp data (with NaN)
P=permute(T,[2,3,1])
P =
P(:,:,1) = NaN 31 38 80 81 30 72 49 35 96 P(:,:,2) = 4 24 64 53 15 63 36 17 24 17 P(:,:,3) = 19 18 35 38 4 18 100 22 27 88
nanmap=isnan(P);
P(nanmap)=-inf;
[~,ranks]=sort(P ,3,'descend');
[~,ranks]=sort(ranks,3);
ranks(nanmap)=nan
ranks =
ranks(:,:,1) = NaN 1 2 1 1 2 2 1 1 1 ranks(:,:,2) = 2 2 1 2 2 1 3 3 3 3 ranks(:,:,3) = 1 3 3 3 3 3 1 2 2 2

1 Kommentar

Matt J
Matt J am 8 Mai 2024
Bearbeitet: Matt J am 8 Mai 2024
Here's a potentially more optimized implementation which requires only 1 sorting op, which is to be done with the attached file sortlidx.
T = randi(100,3,2,5); T(1)=nan; % random temp data (with NaN)
P=permute(T,[2,3,1])
P =
P(:,:,1) = NaN 92 22 10 58 94 78 66 82 30 P(:,:,2) = 87 36 3 8 62 81 82 70 15 48 P(:,:,3) = 6 30 7 72 85 30 83 85 81 58
nanmap=isnan(P);
P(nanmap)=-inf;
[~,I]=sortlidx(P ,3,'descend');
ranks=reshape(1:numel(I), size(P));
ranks(I)=ranks;
[~,~,ranks]=ind2sub(size(P), ranks);
ranks(nanmap)=nan
ranks =
ranks(:,:,1) = NaN 1 1 2 3 1 3 3 1 3 ranks(:,:,2) = 1 2 3 3 2 2 2 2 3 2 ranks(:,:,3) = 2 3 2 1 1 3 1 1 2 1

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

James Tursa
James Tursa am 8 Mai 2024
Bearbeitet: James Tursa am 8 Mai 2024

0 Stimmen

Might be easier to permute first so that your 2D matrices are in the first two spots. Then simply use sort() to get the rank indexing you want. E.g.,
T = randi(100,3,3,4) % random temp data
T =
T(:,:,1) = 37 3 79 39 87 59 85 84 88 T(:,:,2) = 35 43 60 85 38 73 39 35 5 T(:,:,3) = 59 12 80 97 22 42 53 53 22 T(:,:,4) = 40 47 61 21 50 45 1 16 69
P = permute(T,[2,3,1]) % permute the data so grid is first two dimensions
P =
P(:,:,1) = 37 35 59 40 3 43 12 47 79 60 80 61 P(:,:,2) = 39 85 97 21 87 38 22 50 59 73 42 45 P(:,:,3) = 85 39 53 1 84 35 53 16 88 5 22 69
[~,R] = sort(P,3,'descend') % generate the ranks based on 3rd dimension
R =
R(:,:,1) = 3 2 2 1 2 1 3 2 3 2 1 3 R(:,:,2) = 2 3 1 2 3 2 2 1 1 1 2 1 R(:,:,3) = 1 1 3 3 1 3 1 3 2 3 3 2
R(:,:,1) % pick off 1st year ranks
ans = 3x4
3 2 2 1 2 1 3 2 3 2 1 3
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
R(:,:,2) % pick off 2nd year ranks
ans = 3x4
2 3 1 2 3 2 2 1 1 1 2 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
etc.
*** EDIT ***
Needs another step to get the rankings:
n = size(R,1) * size(R,2);
M = reshape(1:n,size(R,1),size(R,2));
K = zeros(size(R));
for k=1:size(R,3)
X = M + n * (R(:,:,k)-1);
K(X(:)) = k;
end
K
K =
K(:,:,1) = 3 3 2 1 3 1 3 2 2 2 1 2 K(:,:,2) = 2 1 1 2 1 2 2 1 3 1 2 3 K(:,:,3) = 1 2 3 3 2 3 1 3 1 3 3 1
Probably a way to do this without looping but I don't see it at the moment. I just saw your NaN comment. What specifically do you want to happen with NaN values? Get lowest ranking, or ...? E.g., to force them to get lowest ranking you could just do this with the sort
[~,R] = sort(P,3,'descend','MissingPlacement','last');

5 Kommentare

John Cruce
John Cruce am 8 Mai 2024
I'm not sure where I'm going astray, but this isn't giving me the desired result. When I manually check the sorted rankings from the permuted matrix with the original matrix, the rankings appear off.
Why is there a need to permute the original matrix? Ultimately, I want a 2D matrix of the same dimensions as the original but for a given year (i.e., 720x1440). For a given year (from year 1 to year 42), I'm seeking a rank (1=highest/warmest, 42=lowest/coldest) for each lat/long pair based on all 42 years.
Am I missing something or is the solution I'm seeking unclear?
Matt J
Matt J am 8 Mai 2024
Bearbeitet: Matt J am 8 Mai 2024
Am I missing something or is the solution I'm seeking unclear?
No way to know, since you haven't demonstrated the defect you see in the results. But given that James and I reached the same solution for you, and given that you haven't cited a problem with the results in James' example, it is likely you are mis-evaluating the results on your own data.
John Cruce
John Cruce am 8 Mai 2024
Bearbeitet: John Cruce am 8 Mai 2024
I believe I see where the confusion lies. The solution proposed yields a matrix of indices for each rank (1 to 42) of temperature. So, for example, in R(:,:,1) I'm seeing what year within the original matrix T the warmest temperature is located (i.e., 2=second year, 3=third year, etc.).
What I'm seeking instead is for each year, a rank value of temperature T at each lat/long. So a value of 1 would tell me that for a given year, that is the warmest value of all 42 years (a value of 2 would say it's the second warmest of all 42 years, etc.). Instead, a value of 1 in the proposed solutions says the warmest value is located in year 1, not that it's the warmest value of all years.
Does that make sense?
I suppose I could take the original matrix and then compare each lat/long point to the rank matrix proposed to back out a temperature rank for a given year, but seems a little backward.
Also how can NaN values be ignored in this solution?
James Tursa
James Tursa am 8 Mai 2024
@John Cruce You're right, this needs another step. See my edit above.
Steven Lord
Steven Lord am 8 Mai 2024
Can you construct a smaller 3-D array for which the solutions @Matt J and @James Tursa provided don't give the answer you expected/wanted and show the answer you did expect? As an example, give us a 3-by-4-by-5 array (something small enough to easily include in a comment) and the 4-by-5 matrix that is the right answer for that array? That concrete example may help us better understand how the provided solutions fail to satisfy your needs.

Melden Sie sich an, um zu kommentieren.

Kategorien

Produkte

Version

R2019b

Tags

Gefragt:

am 8 Mai 2024

Bearbeitet:

am 8 Mai 2024

Community Treasure Hunt

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

Start Hunting!

Translated by