On Average How do you compute the average in APL? Many authors and speakers say: avg←{(+/⍵)÷⍴⍵} The function is often used to demonstrate the beauty and power of the language. It is presented in the About the APLs page of Vector. It is the first program in the Dyalog APL Tutorial (page 10). At the recent Dyalog User Conference in Princeton it was presented in at least three sessions, and in one was described as “the very best APL expression”. Let’s look into it: avg 1 2 3 4 2.5 So far so good. What about avg¨ (1 2) (3 4 5) (6 5 4 3.14159) 1.5 4 4.5353975 The extra blanks hint at the trouble. Application of the monad ↑ to the result brings the problem into relief: ↑ avg¨ (1 2) (3 4 5) (6 5 4 3.14159) 1.5 4 4.5353975 That is, avg should return a scalar rather than a vector result. Now consider: avg 1 2 3 4 2.5 avg 1 2 3 2 avg 1 2 1.5 avg 1 What just happened with the last expression? A few moments of reflection reveal that avg mishandles scalar arguments. What about matrices and higher-ranked arrays? ⎕←data←?3 4⍴10 1 7 4 5 2 0 6 6 9 3 5 8 avg data RANK ERROR avg[0] avg←{(+/⍵)÷⍴⍵} ∧ In summary, the problems with avg←{(+/⍵)÷⍴⍵} are:
Fortunately, a better definition readily obtains. It is somewhat longer than the commonly promulgated version, but fixes its defects: avg1←{(+⌿⍵)÷⍬⍴(⍴⍵),1} avg1 1 2 3 4 2.5 avg1¨ (1 2) (3 4 5) (6 5 4 3.14159) 1.5 4 4.5353975 ↑ avg1¨ (1 2) (3 4 5) (6 5 4 3.14159) 1.5 4 4.5353975 avg1 1 1 avg1 data 4 3.333333333 5 6.333333333 There is one more point:
avg ⍳0 1 avg1 ⍳0 1 I would argue that 0 is a better answer for the average of an empty vector. For example, (+/⍵)÷⍴⍵ ←→ +/⍵÷⍴⍵ and (+⌿⍵)÷⍬⍴(⍴⍵),1 ←→ +⌿⍵÷⍬⍴(⍴⍵),1 for vector ⍵ , except when ⍵ is an empty vector. If instead 0 is that average, then the identity holds for all vectors. Possibly 1 is a reasonable answer, but if so it should be a considered answer and not an unintended consequence of that 0÷0 is 1 . Finally, the common definition of average in J is arguably “the best expression in J”: avgj=: +/ % # avgj 1 2 3 4 2.5 avgj&> 1 2 ; 3 4 5 ; 6 5 4 3.14159 1.5 4 4.5354 avgj data 4 3.33333 5 6.33333 avgj 1 1 avgj i.0 0 Together with the rank operator ("), this definition of the average makes it easy to find the average of various parts of an array. avgj"1 data 4.25 3.5 6.25 ] x=: ? 2 3 4 $ 20 10 7 18 9 2 12 15 5 15 13 18 10 0 5 9 6 14 0 6 4 9 8 15 17 avgj x 5 6 13.5 7.5 8 6 10.5 4.5 12 10.5 16.5 13.5 avgj"3 x 5 6 13.5 7.5 8 6 10.5 4.5 12 10.5 16.5 13.5 avgj"2 x 9 10.6667 17 8 7.66667 4.33333 10 9 avgj"1 x 11 8.5 14 5 6 12.25 avgj"0 x 10 7 18 9 2 12 15 5 15 13 18 10 0 5 9 6 14 0 6 4 9 8 15 17 Also appeared in Vector, Volume 24, Number 2&3, 2010-08.
|