我有一个角度列表,想要摆脱异常值。我的第一个想法是计算中位数。不幸的是,存在“环绕”问题。我不知道为一组角度(或时钟位置)定义中位数的“正确”方法。
我的想法是首先计算平均值,然后使用它来打破对方的圆圈。
Example:
{6, 50, 52, 54, 60, 250} (in degree, 0-360)
average ~ 39
new range [-219, 219) -> new order 250, 6, 50, 52, 54, 60, 250
52 or 54 as median
这是一个好方法,还是可能有更好的我不知道的?
有点相关:This Question显示了计算角度平均值的方法。
答案 0 :(得分:2)
您可以使用您链接的问题中显示的方法:将平均值计算为角度的累积单位矢量的角度。在我看来,这种方法并不适合大型载体。
还有另一种方法适用于加权插值。它不需要任何三角函数,这意味着您可以以度为单位处理数据,而无需将它们转换为弧度。
在这种方法中,所有角度必须在0°和360°之间。如果他们在外面,他们必须被带到这个范围,例如, -5°变为355°。然后你做一个成对加权平均值,你可以在它们的差值大于半圆的情况下调整角度,这样你就可以在角度之间的较短弧度上进行平衡。平均后,得到的角度范围为0°至360°。
def angle_interpol(a1, w1, a2, w2):
"""Weighted avarage of two angles a1, a2 with weights w1, w2
diff = a2 - a1
if diff > 180: a1 += 360
elif diff < -180: a1 -= 360
aa = (w1 * a1 + w2 * a2) / (w1 + w2)
if aa > 360: aa -= 360
elif aa < 0: aa += 360
return aa
def angle_mean(angle):
"""Unweighted average of a list of angles"""
if not angle: return 0
aa = 0.0
ww = 0.0
for a in angle:
aa = angle_interpol(aa, ww, a, 1)
ww += 1
return aa
如果你看一下你的例子{6°,50°,52°,54°,60°,250°},你会注意到所有点位于250°(或-110°)之间的同一个半圆上和70°。使用所提出的平均方法,平均角度为18.67°。这也是{6,50,52,54,60,-110}的线性平均值,这似乎是合理的。中位数在50到52之间。异常值仍然是250°的角度,但是如果你来自-110°则比从250°来的更接近平均值。
另一个例子是{0°,0°,90°}。矢量方法计算atan(0.5)
,即平均约26.6°。建议的方法将30°确定为平均值。
只有当数据在可行角度范围内不均匀分布时,计算圆形平均值才有意义。如果角度相互抵消,那么arctan方法具有奇异性;上面提出的方法只会产生垃圾。
答案 1 :(得分:1)
要获得一组数字的中位数,请对它们进行排序,然后取中间数字。也就是说,如果您按排序顺序排列7个数字,则中位数为第3个数字。
你可以对角度做同样的事情,但结果没什么意义,因为当你有多个角度时,“第一角度”的概念没有明确定义。
要定义第一个角度,您可以对角度进行排序,找到连续角度之间的最大间隙。两个角度之间最大间隙旁边的角度直观地感觉像是一个“第一”角度的好候选者。
答案 2 :(得分:1)
我相信以下方法是有道理的:
中位数是指到所有输入点的距离之和最小的点(对于奇数个输入点,两个输入点之间的整个范围给出相同的总和,因此该范围的中间是通常采取)。在角度是周期性的情况下,两个可能的方向之间的距离应该是最小的,即0和pi之间的距离。
由于最小值是在一个输入点上实现的(或者在奇数情况下是两个连续的,如前所述),因此对于n个角度存在明显的O(n ^ 2)算法。似乎可以通过对角度进行排序,计算第一个距离的总和,并通过跟踪列表中的位置来更新每个连续角度的总和来将其改进为O(n log n)。 ;对映体&#34;底角的下降。