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$
  • $\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 Jul 27 '17 at 8:22
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$
  • $\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 Jul 31 '17 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 Jul 31 '17 at 9:23
  • $\begingroup$ I get {4, 3, 6, 14, 12, 31}, which is correct $\endgroup$ – eldo Jul 31 '17 at 9:50
  • $\begingroup$ Thats odd. I'll give another go! $\endgroup$ – gweeish Jul 31 '17 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 Aug 1 '17 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$
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$
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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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