Wenden Sie EuclideanDistance auf einer bestimmten Ebene in Mathematica an
-
27-10-2019 - |
Frage
Bitte beachten Sie:
daList = {{{21, 18}, {20, 18}, {18, 17}, {20, 15}},
{{21, 18}, {20, 18}, {21, 14}, {21, 14}}};
Ich möchte den Abstand zwischen jedem Punkt in den 2 Unterlisten dieser Liste berechnen:
Ich muss jedoch einen Function
verwenden, um auf der richtigen Ebene anzuwenden:
Function[seqNo,
EuclideanDistance[#, {0, 0}] & /@ daList[[seqNo]]] /@
Range[Length@daList]
out = {{3 Sqrt[85], 2 Sqrt[181], Sqrt[613], 25}, {3 Sqrt[85], 2 Sqrt[181],
7 Sqrt[13], 7 Sqrt[13]}}
Gibt es eine Möglichkeit, diese schwere Funktion dort zu vermeiden? Um die Ebene anzugeben, die meine Funktion mit seqNo als Argument vermeidet?:
EuclideanDistance[#, {0, 0}] & /@ daList
out={EuclideanDistance[{{21, 18}, {20, 18}, {18, 17}, {20, 15}}, {0, 0}],
EuclideanDistance[{{21, 18}, {20, 18}, {21, 14}, {21, 14}}, {0, 0}]}
Lösung
Haben Sie die Level-Spezifikation in Map ausprobiert?
Map[EuclideanDistance[#, {0, 0}] &, daList, {2}]
gibt
{{3 Sqrt[85],2 Sqrt[181],Sqrt[613],25},{3 Sqrt[85],2 Sqrt[181],7 Sqrt[13],7 Sqrt[13]}}
Andere Tipps
Um die Antwort von @Markus zu ergänzen: Wenn Ihr daList
sehr groß und numerisch ist, ist Folgendes viel schneller (wie 30x), wenn auch etwas weniger allgemein:
Sqrt@Total[daList^2,{3}]
Hier ist ein Beispiel:
In[17]:= largeDaList = N@RandomInteger[30,{100000,4,2}];
In[18]:= Map[EuclideanDistance[#,{0,0}]&,largeDaList,{2}]//Short//Timing
Out[18]= {0.953,{{31.7648,34.6699,20.3961,31.305},<<99998>>,{<<18>>,<<2>>,0.}}}
In[19]:= Sqrt@Total[largeDaList^2,{3}]//Short//Timing
Out[19]= {0.031,{{31.7648,34.6699,20.3961,31.305},<<99998>>,{<<18>>,<<2>>,0.}}}
Der Grund dafür ist, dass Funktionen wie Power
und Sqrt
Listable
sind und Sie die Iteration in den Kernel verschieben. Funktionen wie Map
können die zugeordnete Funktion in vielen Fällen auch automatisch kompilieren, in diesem Fall jedoch anscheinend nicht.
EDIT
Auf Anfrage des OP folgt eine Verallgemeinerung auf den Fall eines nicht trivialen Bezugspunkts:
refPoint = {3, 5};
Sqrt@Total[#^2, {3}] &@Transpose[Transpose[daList, {3, 2, 1}] - refPoint, {3, 2, 1}]
Es ist immer noch schnell, aber nicht so präzise wie zuvor. Zum Vergleich ist hier der Code, der auf Map
ing basiert und hier nur geringfügig geändert werden muss:
Map[EuclideanDistance[#, refPoint] &, daList, {2}]
Der Leistungsunterschied bleibt in der gleichen Größenordnung, obwohl sich die vektorisierte Lösung aufgrund der Notwendigkeit nicht trivialer Transpositionen etwas verlangsamt.