# How to map the second highest value in each row of a matrix

I have a matrix with three or more columns called mat. I would like to map the second highest value in each row of mat into its own list, and then take the mean of all the 2nd highest values. With only two rows, I managed to do this by using Min, like this:

h = Map[Min, mat];
Mean[h]


How can I achieve this with three or more rows? I have tried to use RankedMin and RankedMax, but could not get them to work with the Map function.

• Welcome to Mathematica.SE! 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour and check the faqs! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign!
– user9660
Dec 18, 2015 at 10:47
• @Kuba I could not get this to work. When I try this on a matrix with two columns, it returns an error of the type RankedMax::rvec: "Input {{0.757069},{0.211864}} is not a vector of reals or integers.", and so on for each row in mat. In this example the first row is {0.757069},{0.211864}
– bjoj
Dec 18, 2015 at 12:37
• @Kuba Yes, you are right. Is that important? To derive mat I used Transpose to cobine two other (single column) matrices
– bjoj
Dec 18, 2015 at 12:45
• @Kuba You are right. I tested it by making a matrix without the {} around each value, and your suggestion then works. Do you know a way to turn a matrix with columns of lists with numerical values into a normal matrix with columns of numerical values? ...Other than doing it manually? Or put differently, how to cobine all the single-column lists that I have into a normal matrix with many columns (not columns of lists)?
– bjoj
Dec 18, 2015 at 13:34
• @Kuba I ended up using Flatten[] on each list of values, and then Transpose to combine them into a many-column matrix. This worked. Thank you!
– bjoj
Dec 18, 2015 at 14:49

In case this matters performance-wise you could also use RankedMax which is highly optimized for this purpose.

mat = RandomReal[{0, 1}, {10*6, 10000}];

Mean[RankedMax[#, 2] & /@ mat]
(* 0.999801 *)


For large matrices this is an order of magnitude faster.

In:= AbsoluteTiming[r1 = Mean[RankedMax[#, 2] & /@ mat];]

Out= {0.0151883, Null}

In:= AbsoluteTiming[r2 = Mean[(Sort /@ mat)[[All, -2]]];]

Out= {0.112088, Null}

In:= r1 == r2

Out= True

• @kuba my apologies I didn't notice you had already posted this in the comments Dec 19, 2015 at 1:18
• No worries, thanks for the answer and comparison.
– Kuba
Dec 19, 2015 at 7:45
• @AndyRoss Thank you. This works. I had problems using RankedMax initially because my matrix had lists with values in it, for some reason, instead of just values. I managed to fix this by using Flatten on each column, before using transpose to make the final matrix. Afterwards I could use RankedMax
– bjoj
Dec 19, 2015 at 15:52

mat = RandomReal[2., {5, 5}]
(* {{0.124282, 0.382223, 1.49303, 0.869288, 1.44267}, {0.209928,
0.065412, 0.694497, 1.49617, 1.31293}, {1.44424, 1.31737, 0.753354,
0.460729, 1.0257}, {0.94123, 1.03758, 0.346167, 0.754396,
0.0348236}, {0.251986, 0.395477, 0.942587, 0.772752, 0.454348}} *)


To get a list of the second largest number of each row, first sort the rows

Sort /@ mat
(* {{0.124282, 0.382223, 0.869288, 1.44267, 1.49303}, {0.065412,
0.209928, 0.694497, 1.31293, 1.49617}, {0.460729, 0.753354, 1.0257,
1.31737, 1.44424}, {0.0348236, 0.346167, 0.754396, 0.94123,
1.03758}, {0.251986, 0.395477, 0.454348, 0.772752, 0.942587}} *)


Then take the second to last element of each row

(Sort /@ mat)[[All, -2]]
(* {1.44267, 1.31293, 1.31737, 0.94123, 0.772752} *)


And finally, take the Mean

Mean@(Sort /@ mat)[[All, -2]]
(* 1.15739 *)

• This works! Thank you!
– bjoj
Dec 18, 2015 at 12:31