# medians for degree measurements

Sat Jan 23 15:57:00 CET 2010

```Steve Howell <showell30 at yahoo.com> writes:

> I just saw the thread for medians, and it reminded me of a problem
> that I need to solve.  We are writing some Python software for
> sailing, and we need to detect when we've departed from the median
> heading on the leg.  Calculating arithmetic medians is
> straightforward, but compass bearings add a twist.
>
> The numerical median of 1, 2, 3, 4, 5, 6, 359 is 4.  But for
> navigational purposes you would actually order the numbers 359, 1, 2,
> 3, 4, 5, 6, so the desired median heading of the boat is actually 3.
>
> Of course, you could express 359 better as -1 degrees to north, then
> the sequence would be -1, 1, 2, 3, 4, 5, and 6.  And you'd be good.
>
> But that trick does not generalize if you go south instead, as you
> have similar issues with -179, 174, 175, 176, 177, 178, and 179.
>
> Has anybody solved this in Python, either for compass bearings or a
> different domain?  I can think of kind of a brute force solution where
> you keep rotating the sequence until the endpoints are closest
> together mod 360, but I wonder if there is something more elegant.

Here's a simple (too simple?) way to do it:

1. sort the bearings in ascending order
2. find the largest gap between two consecutive bearings
3. cut the circle at this point and now find the median the
normal way

In Python:

>>> def median_bearing(bearings):
...     bearings = sorted(bearings)
...     n = len(bearings)
...     i = max(xrange(n), key=lambda i: (bearings[(i+1)%n] - bearings[i])%360)
...     return bearings[(i + (n+1)//2)%n]
...
>>> median_bearing([1,2,3,4,5,6,359])
3
>>> median_bearing([-179, 174, 175, 176, 177, 178, 179])
177

I guess there may be cases where the results that it gives are still not
very good, as in general there isn't a good notion of median for cyclic
data.  E.g. what would be the median of [0, 180] - it could equally be
090 or 270.  Or the median of [0, 120, 240] has the same problem.  But I
suppose your data couldn't be like this as then it would be ill-advised
to try to apply a notion of median to it.

But it will work well I believe with quite localized data set
with a few, even wildly inaccurate, outliers.  E.g.

>>> median_bearing([123, 124, 125, 125, 126, 10, 240])
125

HTH

--
Arnaud

```