7
$\begingroup$

I am trying to find the minimum combination of absolute values from this matrix

mat = {{-351, -260, -148, -159,   1},
       {-197, -106,    6,   -5, 155},
       {-194, -103,    9,   -2, 158},
       {-104,  -13,   99,   88, 248},
       {  28,  119,  231,  220, 380}};

Basically, one element per column. However, with my current code, two elements from the same column has been selected (which isn't what I want).

For[i = 1, i < Length[diffList] + 1, i++,    
  setMin1 = {};    
  setMin2 = {};    
  setMin3 = {};    
  setMin4 = {};    
  setMin5 = {};    
  For[j = 1, j < Length[diffList[[i]]] + 1, j++,    
    setMin1 = Append[setMin1, Abs[diffList[[i, j, 1]]]];    
    setMin2 = Append[setMin2, Abs[diffList[[i, j, 2]]]];    
    setMin3 = Append[setMin3, Abs[diffList[[i, j, 3]]]];    
    setMin4 = Append[setMin4, Abs[diffList[[i, j, 4]]]];    
    setMin5 = Append[setMin5, Abs[diffList[[i, j, 5]]]];]]

This is what I have at the moment. Any help would be mucho appreciated!

How can we efficiently select the smallest magnitude and combination of elements from each column of a matrix?

$\endgroup$
1
  • $\begingroup$ Hi, welcome to Mathematica.SE, please consider taking the tour so you learn the basic rules of the site. Once you gain enough reputation by making good questions you will be able to vote up and down both questions and answers. Your question has been answered, but its a good idea to wait 24hours for other answers before accepting the best one for you. $\endgroup$
    – rhermans
    Commented Jul 27, 2017 at 8:22

6 Answers 6

5
$\begingroup$

You can also use Composition (@*)

Min @* Abs /@ Transpose[mat]

{28, 13, 6, 2, 1}

To retain the signs:

MinimalBy[Abs] /@ Transpose[mat] // Flatten

{28, -13, 6, -2, 1}

$\endgroup$
6
  • $\begingroup$ Hi Eldo, Just another question (maybe I should have been more specific before). I would like to make sure that only one element per column per row is selected to give the smallest sum. I'm facing the issue of 2 elements per row now. =x Thank you for your help! $\endgroup$
    – gweeish
    Commented Jul 31, 2017 at 9:02
  • $\begingroup$ I tried using the same command for another set of data, and for some reason, the double picking occurred again {{-348 -194 -191 -101 -67 31} {-293 -139 -136 -46 -12 86} {-261 -107 -104 -14 20 118} {-139 15 18 108 142 240} {-151 3 6 96 130 228} {4 158 161 251 285 383}}, with the elements {31,12,14,15,3,4} being selected. $\endgroup$
    – gweeish
    Commented Jul 31, 2017 at 9:23
  • $\begingroup$ I get {4, 3, 6, 14, 12, 31}, which is correct $\endgroup$
    – eldo
    Commented Jul 31, 2017 at 9:50
  • $\begingroup$ Thats odd. I'll give another go! $\endgroup$
    – gweeish
    Commented Jul 31, 2017 at 11:32
  • $\begingroup$ Hi Eldo, With the result you got {4, 3, 6, 14, 12, 31}, the code is taking the elements 3 and 6 from the same row. I'm hoping to grab the smallest combination of elements by taking one element per row and per column. So in this case, either {4, 3, 18, 14, 12, 31} or {4, 15, 6, 14, 12, 31}. does that make sense? Thank you for your help! $\endgroup$
    – gweeish
    Commented Aug 1, 2017 at 1:23
10
$\begingroup$
m = 
  {{-351, -260, -148, -159, 1}, 
   {-197, -106, 6, -5, 155}, 
   {-194, -103, 9, -2, 158}, 
   {-104, -13, 99, 88, 248}, 
   {28, 119, 231, 220, 380}};

Lets not forget that Abs is Listable, so we only have to map Min.

Min /@ Abs[Transpose[m]]

{28, 13, 6, 2, 1}

$\endgroup$
0
5
$\begingroup$

This

mat = {{-351, -260, -148, -159,   1},
       {-197, -106,    6,   -5, 155},
       {-194, -103,    9,   -2, 158},
       {-104,  -13,   99,   88, 248},
       {  28,  119,  231,  220, 380}};
Map[Min[Abs[#]] &, Transpose[mat]]

finds the minimum absolute value element in each column {28, 13, 6, 2, 1}

You can do the same thing without needing to understand # and & by

findminabs[v_] := Min[Abs[v]];
Map[findminabs, Transpose[mat]]
$\endgroup$
0
4
$\begingroup$
MapThread[#2[[First[Ordering[#, 1]]]] &, 
   Transpose[{Abs[mat], mat}, {1, 3, 2}]]

{28, -13, 6, -2, 1}

$\endgroup$
3
$\begingroup$

Since the OP asked for efficiency, here a method that exploits the fact that CompiledFunctions with option RuntimeAttributes->{Listable} thread only to first level:

cMin = Compile[{{x, _Real, 1}},
  Min[x],
  CompilationTarget -> "C",
  RuntimeAttributes -> {Listable},
  Parallelization -> True
  ]

mat = RandomReal[{-1, 1}, {1000, 1000}];
a = cMin[Transpose[Abs[mat]]]; // AbsoluteTiming // First
b = Min /@ Abs[Transpose[mat]]; // AbsoluteTiming // First
a == b

(* 0.007451 *)
(* 0.05298 *)
(* True *)
$\endgroup$
1
$\begingroup$
mat =
  {{-351, -260, -148, -159, 1}, {-197, -106, 6, -5, 155}, 
   {-194, -103, 9, -2, 158}, {-104, -13, 99, 88, 248}, {28, 119, 231, 220, 380}};

To avoid transposition we can use ArrayReduce (new in 12.2)

ArrayReduce[Min @* Abs, mat, 1]

{28, 13, 6, 2, 1}

To retain the signs:

ArrayReduce[Splice @* MinimalBy[Abs], mat, 1]

{28, -13, 6, -2, 1}

Splice came with V 12.1

$\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.