1
$\begingroup$

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.

$\endgroup$
5
  • $\begingroup$ 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! $\endgroup$
    – user9660
    Commented Dec 18, 2015 at 10:47
  • $\begingroup$ @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} $\endgroup$
    – bjoj
    Commented Dec 18, 2015 at 12:37
  • $\begingroup$ @Kuba Yes, you are right. Is that important? To derive mat I used Transpose to cobine two other (single column) matrices $\endgroup$
    – bjoj
    Commented Dec 18, 2015 at 12:45
  • $\begingroup$ @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)? $\endgroup$
    – bjoj
    Commented Dec 18, 2015 at 13:34
  • $\begingroup$ @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! $\endgroup$
    – bjoj
    Commented Dec 18, 2015 at 14:49

5 Answers 5

5
$\begingroup$

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[34]:= AbsoluteTiming[r1 = Mean[RankedMax[#, 2] & /@ mat];]

Out[34]= {0.0151883, Null}

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

Out[35]= {0.112088, Null}

In[36]:= r1 == r2

Out[36]= True
$\endgroup$
3
  • $\begingroup$ @kuba my apologies I didn't notice you had already posted this in the comments $\endgroup$
    – Andy Ross
    Commented Dec 19, 2015 at 1:18
  • $\begingroup$ No worries, thanks for the answer and comparison. $\endgroup$
    – Kuba
    Commented Dec 19, 2015 at 7:45
  • $\begingroup$ @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 $\endgroup$
    – bjoj
    Commented Dec 19, 2015 at 15:52
4
$\begingroup$

This could be your matrix,

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 *)
$\endgroup$
1
  • $\begingroup$ This works! Thank you! $\endgroup$
    – bjoj
    Commented Dec 18, 2015 at 12:31
1
$\begingroup$

With Jason's data

list =
  {{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}};

Using the operator-form of TakeLargest (new in 10.1)

Last /@ TakeLargest[2] /@ list

{1.44267, 1.31293, 1.31737, 0.94123, 0.772752}

Mean[Last /@ TakeLargest[2] /@ list]

1.15739

$\endgroup$
1
$\begingroup$

Grabbing the Jason's matrix and using Nearest:

 list =
  {{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}};

  f[vec_?VectorQ] := Last@Nearest[vec, Max@vec, 2]
  f[mat_?MatrixQ] := Map[f@# &, mat]

  f@list

  (*{1.44267, 1.31293, 1.31737, 0.94123, 0.772752}*)

  Mean@f@list

  (*1.15739*)
$\endgroup$
0
$\begingroup$
list = {{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}}; (* Thanks to @JasonB *)

Last@MaximalBy[#, Identity, 2] & /@ list // Mean

OR

pos = List /@ (First@Ordering[#, -2] & /@ list)
MapThread[Extract, {list, pos}] // Mean

Result:

1.15739

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.