# 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 '15 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 '15 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 '15 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 '15 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 '15 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 – Andy Ross Dec 19 '15 at 1:18
• No worries, thanks for the answer and comparison. – Kuba Dec 19 '15 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 '15 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 '15 at 12:31