algorithm - name - Ángulos promedios... otra vez
seo meta name (11)
¿Qué hay de malo en tomar el conjunto de ángulos como valores reales y simplemente calcular el promedio aritmético de esos números? Entonces obtendría lo intuitivo (0 + 0 + 90) / 3 = 30 grados.
Edición : gracias por los comentarios útiles y señalando que los ángulos pueden exceder de 360. Creo que la respuesta podría ser el promedio aritmético normal reducido "módulo" 360: sumamos todos los valores, dividimos por el número de ángulos y luego restamos / sumamos un múltiplo de 360 para que el resultado se encuentre en el intervalo [0..360).
Quiero calcular el promedio de un conjunto de ángulos, que representa el rumbo de la fuente (0 a 360 grados) - (similar a la dirección del viento)
Sé que se ha discutido antes (varias veces). La respuesta aceptada fue Calcular vectores unitarios desde los ángulos y tomar el ángulo de su promedio .
Sin embargo, esta respuesta define el promedio de una manera no intuitiva. El promedio de 0, 0 y 90 será atan ((sin (0) + sin (0) + sin (90)) / (cos (0) + cos (0) + cos (90))) = atan (1) / 2) = 26.56 grados
Espero que el promedio de 0, 0 y 90 sea de 30 grados.
Así que creo que es justo volver a hacer la pregunta: ¿Cómo calcularía el promedio, por lo que estos ejemplos darán la respuesta intuitiva esperada?
Edición 2014:
Después de hacer esta pregunta, he publicado un artículo en CodeProject que ofrece un análisis exhaustivo. El artículo examina los siguientes problemas de referencia:
- Dada la hora del día [00: 00-24: 00) para cada nacimiento ocurrido en los EE. UU. En el año 2000 - Calcule la hora promedio de nacimiento del día
- Dado un conjunto múltiple de mediciones de dirección desde un transmisor estacionario a un receptor estacionario, utilizando una técnica de medición con un error distribuido normal envuelto - Estime la dirección.
- Dado un conjunto múltiple de estimaciones de acimut entre dos puntos, hechas por humanos "comunes" (suponiendo que están sujetas a un error distribuido normal truncado envuelto) - Estime la dirección.
¿Qué significa incluso la media de los rodamientos de origen? Comience por responder esa pregunta y se acercará más a definir qué quiere decir con el promedio de ángulos.
En mi opinión, un ángulo con tangente igual a 1/2 es la respuesta correcta. Si tengo una fuerza unitaria que me empuja en la dirección del vector (1, 0), otra fuerza que me empuja en la dirección del vector (1, 0) y la tercera fuerza que me empuja en la dirección del vector (0, 1) ), entonces la fuerza resultante (la suma de estas fuerzas) es la fuerza que me empuja en la dirección de (1, 2). Estos son los vectores que representan los rodamientos 0 grados, 0 grados y 90 grados. El ángulo representado por el vector (1, 2) tiene una tangente igual a 1/2.
Respondiendo a tu segunda edición:
Digamos que estamos midiendo la dirección del viento. Nuestras 3 medidas fueron 0, 0 y 90 grados. Dado que todas las mediciones son equivalentemente confiables, ¿por qué nuestra mejor estimación de la dirección del viento no debe ser de 30 grados? configurarlo a 25.56 grados es un sesgo hacia 0 ...
Está bien, aquí hay un problema. El vector unitario con ángulo 0 no tiene las mismas propiedades matemáticas que el número real 0. Utilizando la notación 0v
para representar el vector con el ángulo 0, tenga en cuenta que
0v + 0v = 0v
es falso pero
0 + 0 = 0
es cierto para los números reales. Entonces, si 0v
representa viento con unidad de velocidad y ángulo 0, entonces 0v + 0v
es viento con unidad de doble velocidad y ángulo 0. Y luego, si tenemos un tercer vector de viento (que representaré usando la notación 90v
) que tiene un ángulo de 90 y la velocidad de la unidad, entonces el viento que resulta de la suma de estos vectores tiene un sesgo porque se desplaza a una velocidad de dos unidades en la dirección horizontal, pero solo a la velocidad de la unidad en la dirección vertical.
Aquí está la respuesta que le di a esta misma pregunta:
¿Cómo se calcula el promedio de un conjunto de datos circulares?
Da respuestas en línea con lo que el OP dice que quiere, pero se debe prestar atención a esto:
"También me gustaría enfatizar que a pesar de que este es un verdadero promedio de ángulos, a diferencia de las soluciones vectoriales, eso no significa necesariamente que sea la solución que debería estar usando, el promedio de los vectores unitarios correspondientes puede ser el valor que En realidad debería estar usando ".
Creo que el problema se deriva de cómo se tratan los ángulos superiores a 180 (y los mayores a 360 también). Si reduce los ángulos a un rango de +180 a -180 antes de sumarlos al total, obtendrá algo más razonable:
int AverageOfAngles(int angles[], int count)
{
int total = 0;
for (int index = 0; index < count; index++)
{
int angle = angles[index] % 360;
if (angle > 180) { angle -= 360; }
total += angle;
}
return (int)((float)total/count);
}
En mi opinión, se trata de ángulos, no de vectores. Por esa razón, el promedio de 360 y 0 es realmente 180. El promedio de una vuelta y ninguna vuelta debe ser media vuelta.
Esto es incorrecto en todos los niveles.
Los vectores se suman de acuerdo a las reglas de la suma de vectores. La respuesta "intuitiva, esperada" podría no ser tan intuitiva.
Tomemos el siguiente ejemplo. Si tengo un vector unitario (1, 0), con origen en (0,0) que apunta en la dirección + x y otro (-1, 0) que también tiene su origen en (0,0) que apunta en La dirección -x, ¿cuál debería ser el ángulo "promedio"?
Si simplemente agrego los ángulos y divido entre dos, puedo argumentar que el "promedio" es +90 o -90. ¿Cuál crees que debería ser?
Si agrego los vectores de acuerdo con las reglas de adición de vectores (componente por componente), obtengo lo siguiente:
(1, 0) + (-1, 0) = (0, 0)
En coordenadas polares, es un vector con magnitud cero y ángulo cero.
Entonces, ¿cuál debería ser el ángulo "promedio"? Tengo tres respuestas diferentes aquí para un caso simple.
Creo que la respuesta es que los vectores no obedecen a la misma intuición que los números, porque tienen magnitud y dirección. Tal vez deberías describir qué problema estás resolviendo un poco mejor.
Cualquiera sea la solución que decida, le aconsejo que la base en vectores. Siempre será correcto de esa manera.
Gracias a todos por ayudarme a ver mi problema más claramente.
Encontré lo que estaba buscando. Se llama método mitsuta .
Las entradas y salidas están en el rango [0..360).
Este método es bueno para promediar datos que se muestrearon utilizando intervalos de muestreo constantes.
El método supone que la diferencia entre muestras sucesivas es menor que 180 grados (lo que significa que si no tomamos muestras lo suficientemente rápido, un cambio de 330 grados en la señal muestreada se detectará incorrectamente como un cambio de 30 grados en la otra dirección). inserte un error en el cálculo). ¿Nyquist – Shannon muestrea el teorema de alguien?
Aquí hay un código c ++:
double AngAvrg(const vector<double>& Ang)
{
vector<double>::const_iterator iter= Ang.begin();
double fD = *iter;
double fSigD= *iter;
while (++iter != Ang.end())
{
double fDelta= *iter - fD;
if (fDelta < -180.) fD+= fDelta + 360.;
else if (fDelta > 180.) fD+= fDelta - 360.;
else fD+= fDelta ;
fSigD+= fD;
}
double fAvrg= fSigD / Ang.size();
if (fAvrg >= 360.) return fAvrg -360.;
if (fAvrg < 0. ) return fAvrg +360.;
return fAvrg ;
}
Se explica en la página 51 en epa.gov/scram001/guidance/met/mmgrma.pdf
Gracias MaR por enviar el enlace como un comentario.
Si los datos muestreados son constantes, pero nuestro dispositivo de muestreo tiene una inexactitud con una distribución de Von Mises , será apropiado un cálculo de vectores unitarios.
Podría hacer esto: digamos que tiene un conjunto de ángulos en un angle
matriz, luego, para calcular la matriz primero haga: angle[i] = angle[i] mod 360
, ahora realice un promedio simple sobre la matriz. Entonces, cuando tienes 360, 10, 20, promedias 0, 10 y 20, los resultados son intuitivos.
Tal vez podrías representar los ángulos como cuaterniones y tomar el promedio de estos cuaterniones y convertirlos de nuevo en ángulo.
No sé si te da lo que quieres porque los cuaterniones son más bien rotaciones que ángulos. Tampoco sé si le dará algo diferente a la solución vectorial.
Los cuaterniones en 2D se simplifican a números complejos, así que supongo que son solo vectores, pero tal vez algún algoritmo interesante de promediado de cuaterniones como http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872_2007014421.pdf cuando se simplifica a 2D Se comportará mejor que el simple vector.
[ Tenga en cuenta que la pregunta del OP (pero no el título) parece haber cambiado a una pregunta bastante especializada ("... el promedio de una SECUENCIA de ángulos donde cada adición sucesiva no difiere de la media corriente en más de una cantidad especificada". ) - ver el comentario de @MaR y el mío. Mi siguiente respuesta aborda el título del OP y la mayor parte de la discusión y las respuestas relacionadas. ]
Esta no es una cuestión de lógica o intuición, sino de definición. Esto ha sido discutido en SO antes sin ningún consenso real. Los ángulos deben definirse dentro de un rango (que podría ser -PI a + PI, o 0 a 2 * PI o podría ser -Inf a + Inf. Las respuestas serán diferentes en cada caso.
El "ángulo" del mundo causa confusión, ya que significa cosas diferentes. El ángulo de visión es una cantidad sin signo (y normalmente es PI> theta> 0. En ese caso, los promedios "normales" pueden ser útiles. El ángulo de rotación (por ejemplo, la rotación total si es un patinador sobre hielo) puede o no estar firmado y puede incluir theta> 2 * PI y theta <-2 * PI.
Lo que se define aquí es ángulo = dirección que requiere vectores. Si usa la palabra "dirección" en lugar de "ángulo", habrá capturado la intención del OP (aparente original) y le ayudará a alejarse de las cantidades escalares.
Wikipedia muestra el enfoque correcto cuando los ángulos se definen circularmente de modo que
theta = theta+2*PI*N = theta-2*PI*N
La respuesta para la media NO es un escalar sino un vector. El OP puede sentir que esto no es intuitivo, pero es el único enfoque correcto útil. No podemos redefinir la raíz cuadrada de -4 para que sea -2 porque es más intuitiva, tiene que ser + -2 * i. De manera similar, el promedio de los rodamientos -90 grados y +90 grados es un vector de longitud cero, no de 0.0 grados.
Wikipedia ( http://en.wikipedia.org/wiki/Mean_of_circular_quantities ) tiene una sección especial y estados (las ecuaciones son LaTeX y pueden verse en Wikipedia):
La mayoría de los medios habituales fallan en cantidades circulares, como ángulos, horas del día, partes fraccionarias de números reales. Para esas cantidades necesitas una media de cantidades circulares.
Dado que la media aritmética no es efectiva para los ángulos, se puede usar el siguiente método para obtener tanto un valor promedio como una medida para la varianza de los ángulos:
Convierta todos los ángulos en puntos correspondientes en el círculo unitario, por ejemplo, α a (cosα, sinα). Eso es convertir las coordenadas polares en coordenadas cartesianas. Luego calcula la media aritmética de estos puntos. El punto resultante quedará en el disco de la unidad. Convertir ese punto de nuevo a coordenadas polares. El ángulo es una media razonable de los ángulos de entrada. El radio resultante será 1 si todos los ángulos son iguales. Si los ángulos están distribuidos uniformemente en el círculo, entonces el radio resultante será 0 y no habrá una media circular. En otras palabras, el radio mide la concentración de los ángulos.
Dados los ángulos / alpha_1, / dots, / alpha_n, la media se calcula mediante
M /alpha = /operatorname{atan2}/left(/frac{1}{n}/cdot/sum_{j=1}^n
/ sin / alpha_j, / frac {1} {n} / cdot / sum_ {j = 1} ^ n / cos / alpha_j / derecha)
utilizando la variante atan2 de la función arcotangente, o
M /alpha = /arg/left(/frac{1}{n}/cdot/sum_{j=1}^n
/ exp (i / cdot / alpha_j) / right)
utilizando números complejos.
Tenga en cuenta que en la pregunta del OP, un ángulo de 0 es puramente arbitrario; no hay nada especial en que el viento provenga de 0 en lugar de 180 (excepto que en este hemisferio hace más frío en la bicicleta). Intente cambiar de 0,0,90 a 289, 289, 379 y vea cómo la aritmética simple ya no funciona.
(Hay algunas distribuciones donde los ángulos de 0 y PI tienen un significado especial, pero no están dentro del alcance aquí).
Aquí hay algunas discusiones previas intensas que reflejan la distribución actual de las vistas :-)
http://mathforum.org/library/drmath/view/53924.html
¿Cómo se calcula el promedio de un conjunto de datos circulares?
Edición: algoritmo equivalente, pero más robusto (y más simple):
- divide los ángulos en 2 grupos, [0-180) y [180-360)
- promedio numéricamente ambos grupos
- Promedio de los promedios de 2 grupos con ponderación adecuada.
- si ocurrió el envolvimiento, corríjalo en 180˚
Esto funciona porque el promedio de números funciona "lógicamente" si todos los ángulos están en el mismo hemicírculo. Luego, demoramos la obtención del error de enrollamiento hasta el último paso, donde se detecta y corrige fácilmente. También introduje un código para manejar casos de ángulos opuestos. Si los promedios son opuestos, favorecemos el hemisferio que tenía más ángulos, y en el caso de ángulos iguales en ambos hemisferios, devolvemos None
porque ningún promedio tendría sentido.
El nuevo código:
def averageAngles2(angles):
newAngles = [a % 360 for a in angles];
smallAngles = []
largeAngles = []
# split the angles into 2 groups: [0-180) and [180-360)
for angle in newAngles:
if angle < 180:
smallAngles.append(angle)
else:
largeAngles.append(angle)
smallCount = len(smallAngles)
largeCount = len(largeAngles)
#averaging each of the groups will work with standard averages
smallAverage = sum(smallAngles) / float(smallCount) if smallCount else 0
largeAverage = sum(largeAngles) / float(largeCount) if largeCount else 0
if smallCount == 0:
return largeAverage
if largeCount == 0:
return smallAverage
average = (smallAverage * smallCount + largeAverage * largeCount) / /
float(smallCount + largeCount)
if largeAverage < smallAverage + 180:
# average will not hit wraparound
return average
elif largeAverage > smallAverage + 180:
# average will hit wraparound, so will be off by 180 degrees
return (average + 180) % 360
else:
# opposite angles: return whichever has more weight
if smallCount > largeCount:
return smallAverage
elif smallCount < largeCount:
return largeAverage
else:
return None
>>> averageAngles2([0, 0, 90])
30.0
>>> averageAngles2([30, 350])
10.0
>>> averageAngles2([0, 200])
280.0
Aquí hay un algoritmo ligeramente ingenuo:
- eliminar todos los ángulos opuestos de la lista
- tomar un par de angulos
- gírelos al primer y segundo cuadrante y promedie
- gire el ángulo promedio hacia atrás en la misma cantidad
- para cada ángulo restante, promedie de la misma manera, pero con un peso sucesivamente creciente al ángulo compuesto
algo de código python (paso 1 no implementado)
def averageAngles(angles):
newAngles = [a % 360 for a in angles];
average = 0
weight = 0
for ang in newAngles:
theta = 0
if 0 < ang - average <= 180:
theta = 180 - ang
else:
theta = 180 - average
r_ang = (ang + theta) % 360
r_avg = (average + theta) % 360
average = ((r_avg * weight + r_ang) / float(weight + 1) - theta) % 360
weight += 1
return average