Применить EuclideanDistance на определенном уровне в Mathematica - PullRequest
2 голосов
/ 07 сентября 2011

Пожалуйста, примите во внимание:

daList = {{{21, 18}, {20, 18}, {18, 17}, {20, 15}}, 
          {{21, 18}, {20, 18}, {21, 14}, {21, 14}}};

Я хотел бы вычислить расстояние между каждой точкой в ​​2 подсписках этого списка:

И все же мне нужно использовать Functionприменить на правильном уровне:

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]}}

Есть ли способ избежать этой тяжелой функции там?Чтобы указать уровень, избегающий моей функции с seqNo в качестве аргумента?:

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}]}

Ответы [ 2 ]

6 голосов
/ 07 сентября 2011

В дополнение к ответу @Markus: если ваш daList очень большой и числовой, следующее будет намного быстрее (например, 30x), хотя и несколько менее общим:

Sqrt@Total[daList^2,{3}]

Вот пример:

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.}}}

Причина в том, что такие функции, как Power и Sqrt равны Listable, и вы вводите итерацию в ядро. Такие функции, как Map, также могут автоматически компилировать сопоставленную функцию во многих случаях, но, очевидно, не в этом случае.

EDIT

запрос Per OP, вот это обобщение на случай нетривиальной точки отсчета:

refPoint = {3, 5};
Sqrt@Total[#^2, {3}] &@Transpose[Transpose[daList, {3, 2, 1}] - refPoint, {3, 2, 1}]

Это все еще быстро, но не так кратко, как раньше. Для сравнения, вот код, основанный на Map - ping, который требует только тривиальной модификации:

Map[EuclideanDistance[#, refPoint] &, daList, {2}]

Разница в производительности остается того же порядка, хотя векторизованное решение немного замедляется из-за необходимости нетривиальных транспозиций.

6 голосов
/ 07 сентября 2011

Вы пробовали спецификацию уровня в карте?

Map[EuclideanDistance[#, {0, 0}] &, daList, {2}]

дает

{{3 Sqrt[85],2 Sqrt[181],Sqrt[613],25},{3 Sqrt[85],2 Sqrt[181],7 Sqrt[13],7 Sqrt[13]}}
...