How to locate an entire column based on one value?

I have a 25x420 matrix. I want to locate the median number within the matrix. Once the median is located, I want to call the column that it came out of. If i do "median(t)" it gives the median of each column but from there I can call the total median value and its column of values.
columns = 25;
rows = 420;
t = rand(rows,columns);

Answers (1)

The way the median is calculated may not exactly match any of the values in the matrix.
The solutiion to that problem is to use the ismembertol function to find the element or elements that are the closest match to it. That returns a logical array, and using find with that result will return the rows and columns of the closest matches that ismembertol returns.
Try something like this —
columns = 25;
rows = 420;
t = rand(rows,columns);
tmed = median(t, 'all')
tmed = 0.5053
[r,c] = find(ismembertol(t, tmed, 1E-4));
row_col = [r c]
row_col = 2x2
111 3 320 19
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
idx = sub2ind(size(t), r, c)
idx = 2x1
951 7880
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t(idx)
ans = 2x1
0.5053 0.5052
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
.
EDIT — Corrected typographical errors.

5 Comments

Wow, I didn't expect that the median would not necessarily be one of the values.
% Create sample data.
data = rand(1000, 1000);
% Have it compute the median.
m = median(data, "all")
m = 0.5009
% See if it's actually in the data, like we'd expect.
[rows, cols] = find(data == m)
rows = 0x1 empty double column vector cols = 0x1 empty double column vector
When there are an even number of input values, then the median is the mean of the two central values. If there are duplicate values, then potentially the two central values will happen to be identical and so the median would be the same as the central values... but in that case, you would have to expect that the source column would match multiple columns. If there are no duplicates, then with an even number of values the median will not exactly match any of the input values.
It is not completely clear whether the position of the median is desired per row or for the overall matrix.
Either way, with there being an even number of entries per row and for the overall matrix, the position of the median would have to be either empty or else a list of at least two values.
Star Strider,
Thanks for the answer. I too did not know that is how the median function works. Thank you for the insight. For the solution you gave, i am looking for an output of a 1x420 matrix, not a 2x1. Also after I locate that value (or something close) in a column (1x420) I would like to output that (1x420) all in one seamless operation. I can spend time locating each one but where its really important is having a scpript that can do it all in one run without having to check the command window or the workspace. Any tips?
My pleasure!
I limited this to a small matrix for ease of interpretation and readability. Everything here would also apply to your (25x420) matrix.
Just using median will return the column medians of a matrix —
A = randn(10)
A = 10x10
-0.1840 1.0885 -2.0206 -1.1134 -0.8050 -1.0294 0.2714 1.1347 -0.0150 -0.4304 -0.4164 -0.2513 -0.9963 0.0027 -1.9010 -0.2864 -0.8389 -1.1578 -0.4903 -0.4042 0.0074 -0.7934 0.1429 -0.9668 -1.1607 -0.9066 0.3446 -1.1123 0.2136 1.1778 -0.3832 2.2025 -1.4934 0.3030 -0.3217 -0.1841 -0.3007 -1.4484 -0.3797 0.7890 0.0230 1.9308 -0.9886 0.4529 0.5115 0.8189 0.2398 0.5702 1.3789 -0.3604 0.4196 -0.6768 0.7539 -1.2780 -0.2931 0.4088 -1.7036 -0.3930 -2.7188 -0.7861 -0.0164 -0.2707 -1.3897 -0.6175 -0.7291 0.5047 1.1061 1.8219 1.0016 0.5403 -0.7049 0.1320 -1.3270 -0.4939 0.6516 0.1642 -1.3163 -1.7062 -0.0860 -1.2845 0.4395 1.5823 0.1089 -0.9712 0.1382 -0.4037 1.0458 0.3306 -3.4837 0.0383 -0.4066 1.8031 0.5805 -0.1327 -1.8988 0.7264 1.1519 0.0072 -1.3220 0.2506
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ColMed = median(A)
ColMed = 1x10
-0.1002 0.6102 -0.9924 -0.5557 -0.5254 -0.0100 0.2556 -0.1929 -0.2328 -0.1610
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Check1 = median(A,'all') == median(ColMed) % Is The Matrix Median Equal To The Medain Of The Column Medians?
Check1 = logical
0
Look = [median(A,'all') median(ColMed)] % Show Their Individual Values
Look = 1x2
-0.2177 -0.1770
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Check2 = ColMed == median(ColMed) % Is The Median Of The Column Medians Equal To Any Of Them?
Check2 = 1x10 logical array
0 0 0 0 0 0 0 0 0 0
[r,c] = find(ismembertol(A, Look(1), 1E-2));
row_col = [r c]
row_col = 3x2
1 1 2 2 4 6
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
idx = sub2ind(size(A), r, c)
idx = 3x1
1 12 54
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
A(idx)
ans = 3x1
-0.1840 -0.2513 -0.1841
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
However, the median of the entire array may not equal the median of the column medians, and the median of the column medians may not be equal to any of them.
Your matrix has an even number of elements (10500), so it is not likely that any one of them will equal the median of the matrix.
It may not be possible to do what you describe wanting to do. (I am not even certain what that is.)
.
Since the input is 25 x 420 and the desired output is 1 x 420 then the per-column median is desired. That is an odd number of entries in the columns, so (provided that there are no nan values) the per-column median will be exactly the same as (at least one of) the rows.
A = rand(25,9);
Medians = median(A);
tic
Per_row_position = sum(cumprod(Medians ~= A)) + 1;
toc
Elapsed time is 0.009425 seconds.
A
A = 25x9
0.2929 0.0002 0.6991 0.6386 0.9287 0.4889 0.4289 0.5787 0.8547 0.3655 0.1354 0.6275 0.6950 0.6883 0.8430 0.3727 0.2921 0.6618 0.3457 0.0778 0.2939 0.4399 0.9086 0.4457 0.5634 0.0411 0.9461 0.4961 0.5700 0.9381 0.4805 0.9934 0.0828 0.7613 0.9223 0.0802 0.7434 0.8918 0.5773 0.0723 0.2984 0.9813 0.1776 0.1028 0.5910 0.8836 0.6333 0.4246 0.3437 0.6069 0.6538 0.7859 0.5676 0.6423 0.0592 0.1362 0.6600 0.2060 0.0555 0.3239 0.7298 0.0782 0.3453 0.7516 0.6257 0.8540 0.9461 0.9035 0.2747 0.4924 0.0449 0.1229 0.4251 0.2896 0.8255 0.2323 0.1255 0.6340 0.8271 0.0264 0.2677 0.7647 0.2324 0.6675 0.0428 0.2056 0.0075 0.4890 0.6607 0.5377
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Medians
Medians = 1x9
0.4251 0.3908 0.4670 0.4922 0.6719 0.4889 0.5199 0.5676 0.3242
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Per_row_position
Per_row_position = 1x9
9 25 21 18 22 1 18 6 11
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
The sum(cumprod) is a trick to locate the positions of matching entries in a parallel manner. It is effectively a
tic
Per_row_position2 = arrayfun(@(IDX) find(A(:,IDX)==Medians(IDX),1), 1:size(A,2))
Per_row_position2 = 1x9
9 25 21 18 22 1 18 6 11
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
toc
Elapsed time is 0.015615 seconds.
... except that it takes more memory, and is a bit faster.

Sign in to comment.

Categories

Products

Release

R2023b

Asked:

on 30 Aug 2024

Commented:

on 3 Sep 2024

Community Treasure Hunt

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

Start Hunting!