5
$\begingroup$

I have a dataset like:

set1 = {{-16.7057, -10.7875, -26.8102}, {-13.2357, 25.903, 13.9369},
        {22.6074,  3.4955, -30.795}, {8.31895, -15.6811, 42.3093}};
set2 = {{-16.705, -10.787, -26.81}, {-13.236, 25.903, 13.937},
        {22.607,  3.495, -30.795}, {8.319, -15.681, 42.309}}

They are pretty close to each other. Now I want to take the Norm of each element of set1[[i]] and subtract it from Norm of each element of the set2[[i]]. And get the output as {a1, a2, a3, a4}. How can I do that without using any loop like For loop?


I just want to add few things for the sake of completeness if the sets are like below then what should be the action:

set1b = {{{-16.7056, -10.78745,-26.81020}, {-13.235671, 25.903009, 13.936884}, {22.6074, 3.495498, -30.79496}, {8.3189, -15.681, 42.309}}, {{1.7960000, 34.50099, -10.9480`}, {-22.420000, -10.4510000, 24.980}, {1.183999,-42.707000000, -17.586999999}, {17.47500, 20.652000, 9.18399}}};

set2b = {{{-16.705`, -10.787`, -26.81`}, {-13.236`, 25.903`, 13.937`}, {22.607`, 3.495`, -30.795`}, {8.319`, -15.681`, 42.309`}}, {{1.796`, 34.501`, -10.948`}, {-22.42`, -10.451`, 24.981`}, {1.184`, -42.707`, -17.587`}, {17.475`, 20.652`,  9.184`}}};

Editted last part

$\endgroup$
  • 2
    $\begingroup$ It's very annoying when people wait for an answer to then change the rules of the question. Please don't do that in the future. Read about moving the goalpost $\endgroup$ – rhermans Jul 19 '18 at 19:16
  • $\begingroup$ I am sorry...never do it again $\endgroup$ – Bikash Jul 19 '18 at 19:19
4
$\begingroup$
ClearAll[normDif]
normDif = Apply[Subtract, Sqrt @ Total[{##}^2, {-1}], {0}] &;

normDif[set1, set2]

{0.000672543, -0.000166313, 0.000281282, 0.00030175}

normDif[set1b, set2b]

{{0.000606338, -0.000177899, 0.00024899, -0.0000181312},
{-9.51991*10^-6, -0.000710573, -2.60074*10^-8, -3.2146*10^-6}}

Timings:

SeedRandom[1]
{s1, s2} = RandomReal[1000, {2, 1000000, 3}];

r1 = normDif[s1, s2]; // RepeatedTiming // First

0.0887

r2 = Norm /@ s1 - Norm /@ s2; // RepeatedTiming // First

0.158

r3 = Apply[Subtract, Map[Norm] /@ {s1, s2}]; //  RepeatedTiming // First

0.155

Norm /@ {Chop[r1 - r2], Chop[r1 - r3]}

{0, 0}

Did not include Subtract @@ MapAt[Norm, {s1, s2}, {All, All}] in timing experiments because computation was aborted due to limitations of the free Wolfram Cloud plan.

$\endgroup$
  • $\begingroup$ Thank you very much $\endgroup$ – Bikash Jul 19 '18 at 20:29
5
$\begingroup$

You may use the levelspec syntax of Map with Subtract.

Norm is Maped to the second last level of the list; the vectors. Subtract is then Applyed to the items in the first level of the list.

Subtract @@ Map[Norm, {set1, set2}, {-2}]
{0.000672543,-0.000166313,0.000281282,0.00030175}
Subtract @@ Map[Norm, {set1b, set2b}, {-2}]
{{0.000606338,-0.000177899,0.00024899,-0.0000181312},
 {-9.51991*10^-6,-0.000710573,-2.60074*10^-8,-3.2146*10^-6}}

Hope this helps.

$\endgroup$
3
$\begingroup$
Subtract @@ MapAt[
  Norm
  , {set1, set2}
  , {All, All}
  ]

{0.000672543, -0.000166313, 0.000281282, 0.00030175}

Equivalently

Apply[Subtract, Map[Norm] /@ {set1, set2}]

Use Join[set1b, set2b] instead of {set1, set2} for the new case.

$\endgroup$
  • $\begingroup$ Thanks for the answer: I have added some edit to the question. Please have a look. $\endgroup$ – Bikash Jul 19 '18 at 19:10
3
$\begingroup$
Norm /@ set1 - Norm /@ set2

If there are extra brackets, then:

newset1 = set1[[1]]

and so forth.

$\endgroup$
  • $\begingroup$ Thanks for the answer: I have added some edit to the question. Please have a look. $\endgroup$ – Bikash Jul 19 '18 at 19:10
  • $\begingroup$ Then replace: newset1 = set1[[1]] to eliminate the outer brackets. $\endgroup$ – David G. Stork Jul 19 '18 at 19:11
  • 2
    $\begingroup$ David, it is not extra brackets; set1b and set2b are 2X4X3 arrays. $\endgroup$ – kglr Jul 19 '18 at 21:14
2
$\begingroup$

If it is about speed, one can do slightly faster (at least on my machine) as follows:

SeedRandom[1]
{s1, s2} = RandomReal[1000, {2, 1000000, 3}];

r1 = normDif[s1, s2]; // RepeatedTiming // First

r4 = Subtract[
     Sqrt[(s1^2).ConstantArray[1., 3]],
     Sqrt[(s2^2).ConstantArray[1., 3]]
     ]; // RepeatedTiming // First

r1 == r4

0.0663

0.024

True

Also quite nice, drawing some more attention to the really useful function NDSolve`FEM`MapThreadDot that was shown to me by user21:

r5 = Subtract[
     Sqrt[NDSolve`FEM`MapThreadDot[s1, s1]],
     Sqrt[NDSolve`FEM`MapThreadDot[s2, s2]]
     ]; // RepeatedTiming // First

r1 == r5

0.033

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.