4
$\begingroup$

I have a multiple datasets that contains thousands of rows and thousands of columns, and from that I'm trying to extract the row that contains the smallest column value from the entire dataset. Depending on what dataset I am using though, that lowest values position may vary. For example, if I have the following set

a = {{2.5,3.4,5.2,7.3,10},{0.1,7.5,8.9,25,7},{4.6,6.8,1,.75,.25}} b={{2.5,3.4,5.2,7.3,10},{0.9,7.5,8.9,25,7},{4.6,6.8,1,.75,.25} To find the minimum value of this array I'd just do

Min[a] and Min[b]

and that should return 0.1 for a and .25 for b, now I want to see the entire row that contains that 0.1 value and then another row that contains the .25 value, so {0.1,7.5,8.9,25,7} and {4.6,6.8,1,.75,.25}. I tried

Select[a,Min[a]] 

to get the row from a but that doesn't return anything. Am I missing something from my select statement, or is there another way I should be going about this?

$\endgroup$
1
  • 6
    $\begingroup$ Try Select[a, MemberQ[#, Min[a]] &] $\endgroup$ Sep 18 at 1:08
7
$\begingroup$

We could use MinimalBy[Min] to find such rows. Note that a list of rows is returned since there could be more than one row that contains the minimal element.

a // MinimalBy[Min]
(* {{0.1, 7.5, 8.9, 25, 7}} *)

b // MinimalBy[Min]
(* {{4.6, 6.8, 1, 0.75, 0.25}} *)

{{1, 2, 3}, {1, 4, 5}, {2, 4, 6}} // MinimalBy[Min]
(* {{1, 2, 3}, {1, 4, 5}} *)
$\endgroup$
2
$\begingroup$

The following implementation will return any rows that contain the minimum:

Part[#, Map[First, Position[#, Min[#]], 1]] & /@ {a, b}

{{{0.1, 7.5, 8.9, 25, 7}}, {{4.6, 6.8, 1, 0.75, 0.25}}}

A minor improvement that I can think of is that row(s) can be further selected/filtered based on where the Min occurs, just in case you need that flexibility. After finding the Position of the min values, the list will have to be processed further, though.

$\endgroup$
2
$\begingroup$

We can use Nearest to get the row indices containing the minimal element:

minmin1 = #[[Nearest[Map[Min][#] -> "Index"] @ Min[#]]] &;

minmin1  @ a
{{0.1, 7.5, 8.9, 25, 7}}
minmin1 @ b
{{4.6, 6.8, 1, 0.75, 0.25}}
minmin1 @ {{1, 2, 3}, {1, 4, 5}, {2, 4, 6}}
{{1, 2, 3}, {1, 4, 5}}

If it is ok to get a single row as output (or the input matrix contains a single row containing min) then we can also use Ordering:

minmin2 = #[[Ordering[Map[Min] @ #, 1]]] &;

minmin2 @ a
{{0.1, 7.5, 8.9, 25, 7}}
minmin2 @ b
{{4.6, 6.8, 1, 0.75, 0.25}}
minmin2 @ {{1, 2, 3}, {1, 4, 5}, {2, 4, 6}}
{{1, 2, 3}}

Both are faster than MinimalBy[Min] (from WReach's answer) and Part[#, Map[First, Position[#, Min[#]], 1]] & (from Syed's answer) for input data with a single row containing the minimum.

Timings:

1. Input data with single row containing the minimum:

SeedRandom[1];

test1 = RandomReal[1, {5000, 5000}];
(res1 = test1 // MinimalBy[Min];) // RepeatedTiming // First
1.00
(res2 = Part[#, Map[First, Position[#, Min[#]], 1]] &@test1;) // RepeatedTiming // First
5.31
(res3 = minmin1 @ test1;) // RepeatedTiming // First
0.063
(res4 = minmin2 @ test1;) // RepeatedTiming // First
0.049
res1 == res2 == res3 == res4
True

2. Input data with many rows containing the minimum:

SeedRandom[1];

test2 = RandomInteger[100, {5000, 5000}];

(res1 = test2 // MinimalBy[Min];) // RepeatedTiming // First
0.13
(res2 = Part[#, Map[First, Position[#, Min[#]], 1]] &@test2;) // 

RepeatedTiming // First

47.
(res3 = minmin1@test2;) // RepeatedTiming // First
0.161
(res4 = minmin2@test2;) // RepeatedTiming // First
0.041
Length /@ {res1, res2, res3, res4}
{5000, 247270, 5000, 1}
res1 == res3
True

3. Input data with not too many rows containing the minimum:

SeedRandom[1];

test3 = RandomInteger[10^5, {5000, 5000}];

(res1 = test3 // MinimalBy[Min];) // RepeatedTiming // First
0.038
(res2 = Part[#, Map[First, Position[#, Min[#]], 1]] &@test3;) // 

RepeatedTiming // First

2.05
(res3 = minmin1@test3;) // RepeatedTiming // First
 0.0536
(res4 = minmin2@test3;) // RepeatedTiming // First
 0.0340
Length /@ {res1, res2, res3, res4}
{238, 242, 238, 1}
res1 == res3
True
$\endgroup$

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