medians for degree measurements
arnodel at googlemail.com
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
>>> 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([-179, 174, 175, 176, 177, 178, 179])
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])
More information about the Python-list