Eu quero calcular a média de um conjunto de dados circulares. Por exemplo, eu posso ter várias amostras da leitura de uma bússola. O problema, é claro, é como lidar com a envolvente. O mesmo algoritmo pode ser útil para um relógio.
A questão real é mais complicada - o que as estatísticas significam em uma esfera ou em um espaço algébrico que "envolve", por exemplo, o grupo aditivo mod n. A resposta pode não ser única, por exemplo, a média de 359 graus e 1 grau pode ser 0 ou 180, mas estatisticamente 0 parece melhor.
Este é um problema de programação real para mim e estou tentando fazer com que não pareça apenas um problema de matemática.
Respostas:
Calcule vetores unitários dos ângulos e calcule o ângulo da média.
fonte
Esta questão é examinada em detalhes no livro: "Statistics On Spheres", Geoffrey S. Watson, Universidade de Arkansas, Lecture Notes in the Mathematics Sciences, 1983 John Wiley & Sons, Inc., como mencionado em http: //catless.ncl. ac.uk/Risks/7.44.html#subj4 por Bruce Karsh.
Uma boa maneira de estimar um ângulo médio, A, a partir de um conjunto de medidas de ângulo a [i] 0 <= i
O método dado por starblue é computacionalmente equivalente, mas seus motivos são mais claros e provavelmente programaticamente mais eficientes, e também funcionam bem no caso zero, então parabéns a ele.
O assunto agora é explorado com mais detalhes na Wikipedia e com outros usos, como partes fracionárias.
fonte
Vejo o problema - por exemplo, se você tem um ângulo de 45 'e um ângulo de 315', a média "natural" seria 180 ', mas o valor que você deseja é realmente 0'.
Eu acho que Starblue gosta de algo. Apenas calcule as coordenadas cartesianas (x, y) para cada ângulo e adicione os vetores resultantes juntos. O deslocamento angular do vetor final deve ser o resultado desejado.
Estou ignorando agora que uma direção da bússola começa no norte e vai no sentido horário, enquanto as coordenadas cartesianas "normais" começam com zero ao longo do eixo X e depois no sentido anti-horário. A matemática deve funcionar da mesma maneira, independentemente.
fonte
cos()
,sin()
eatan2()
dar aproximações (bons, mas ainda fora por 1 ou 2 ulps) assim que mais você média, mais erros que você incluir.PARA O CASO ESPECIAL DE DOIS ANGLES:
A resposta ((a + b) mod 360) / 2 está ERRADA . Para os ângulos 350 e 2, o ponto mais próximo é 356, não 176.
O vetor unitário e as soluções trigonométricas podem ser muito caros.
O que eu tenho de um pouco de mexer é:
fonte
A ackb está certa de que essas soluções baseadas em vetores não podem ser consideradas médias reais dos ângulos, elas são apenas uma média das contrapartes dos vetores unitários. No entanto, a solução sugerida pelo ackb não parece matematicamente correta.
A seguir, é apresentada uma solução matematicamente derivada do objetivo de minimizar (ângulo [i] - ângulo médio) ^ 2 (onde a diferença é corrigida, se necessário), o que a torna uma verdadeira média aritmética dos ângulos.
Primeiro, precisamos examinar exatamente em quais casos a diferença entre os ângulos é diferente da diferença entre os números normais. Considere os ângulos x e y, se y> = x - 180 e y <= x + 180, então podemos usar a diferença (xy) diretamente. Caso contrário, se a primeira condição não for atendida, devemos usar (y + 360) no cálculo em vez de y. Correspondente, se a segunda condição não for atendida, devemos usar (y-360) em vez de y. Como a equação da curva estamos minimizando apenas as mudanças nos pontos em que essas desigualdades mudam de verdadeiro para falso ou vice-versa, podemos separar o intervalo [0,360) completo em um conjunto de segmentos, separados por esses pontos. Então, precisamos encontrar apenas o mínimo de cada um desses segmentos e, em seguida, o mínimo do mínimo de cada segmento, que é a média.
Aqui está uma imagem demonstrando onde os problemas ocorrem no cálculo das diferenças de ângulo. Se x estiver na área cinza, haverá um problema.
Para minimizar uma variável, dependendo da curva, podemos tomar a derivada do que queremos minimizar e depois encontrar o ponto de virada (que é onde a derivada = 0).
Aqui aplicaremos a idéia de minimizar a diferença ao quadrado para derivar a fórmula da média aritmética comum: sum (a [i]) / n. A curva y = soma ((a [i] -x) ^ 2) pode ser minimizada desta maneira:
Agora, aplicando-o a curvas com nossas diferenças ajustadas:
b = subconjunto de a onde a diferença (angular) correta a [i] -xc = subconjunto de a onde a diferença (angular) correta (a [i] -360) -x cn = tamanho do cd = subconjunto de a onde o diferença (angular) correta (a [i] +360) -x dn = tamanho de d
Isso por si só não é suficiente para obter o mínimo, enquanto trabalha para valores normais, que tem um conjunto ilimitado, portanto o resultado definitivamente ficará dentro do intervalo do conjunto e, portanto, é válido. Precisamos do mínimo dentro de um intervalo (definido pelo segmento). Se o mínimo for menor que o limite inferior do nosso segmento, o mínimo desse segmento deverá estar no limite inferior (porque as curvas quadráticas têm apenas 1 ponto de viragem) e se o mínimo for maior que o limite superior do segmento, o mínimo do segmento estará no limite superior. Depois de termos o mínimo para cada segmento, simplesmente encontramos o que tem o menor valor para o que estamos minimizando (soma ((b [i] -x) ^ 2) + soma (((c [i] -360 ) -b) ^ 2) + soma (((d [i] +360) -c) ^ 2)).
Aqui está uma imagem da curva, que mostra como ela muda nos pontos em que x = (a [i] +180)% 360. O conjunto de dados em questão é {65,92,230,320,250}.
Aqui está uma implementação do algoritmo em Java, incluindo algumas otimizações, sua complexidade é O (nlogn). Ele pode ser reduzido para O (n) se você substituir a classificação baseada em comparação por uma classificação não baseada em comparação, como a classificação radix.
A média aritmética de um conjunto de ângulos pode não concordar com sua ideia intuitiva de qual deve ser a média. Por exemplo, a média aritmética do conjunto {179,179,0,181,181} é 216 (e 144). A resposta em que você pensa imediatamente é provavelmente 180, no entanto, é sabido que a média aritmética é fortemente afetada pelos valores das arestas. Lembre-se também de que ângulos não são vetores, por mais atraente que possa parecer ao lidar com ângulos algumas vezes.
É claro que esse algoritmo também se aplica a todas as quantidades que obedecem à aritmética modular (com ajuste mínimo), como a hora do dia.
Eu também gostaria de enfatizar que, embora essa seja uma média real de ângulos, diferentemente das soluções vetoriais, isso não significa necessariamente que é a solução que você deve usar, a média dos vetores unitários correspondentes pode muito bem ser o valor que você realmente deveria estar usando.
fonte
Você precisa definir a média com mais precisão. Para o caso específico de dois ângulos, posso pensar em dois cenários diferentes:
Não vejo como a segunda alternativa possa ser generalizada para o caso de mais de dois ângulos.
fonte
Como todas as médias, a resposta depende da escolha da métrica. Para uma determinada métrica M, a média de alguns ângulos a_k em [-pi, pi] para k em [1, N] é o ângulo a_M que minimiza a soma das distâncias ao quadrado d ^ 2_M (a_M, a_k). Para uma média ponderada, basta incluir na soma os pesos w_k (de modo que sum_k w_k = 1). Isso é,
a_M = arg min_x soma_k w_k d ^ 2_M (x, a_k)
Duas opções comuns de métricas são as métricas de Frobenius e Riemann. Para a métrica Frobenius, existe uma fórmula direta que corresponde à noção usual de rumo médio nas estatísticas circulares. Veja "Médias e médias no grupo de rotações", Maher Moakher, SIAM Journal on Matrix Analysis and Applications, Volume 24, Edição 1, 2002, para obter detalhes.
http://link.aip.org/link/?SJMAEL/24/1/1
Aqui está uma função para o GNU Octave 3.2.4 que faz o cálculo:
fonte
Eu gostaria de compartilhar um método que usei com um microcontrolador que não possui recursos de ponto flutuante ou trigonometria. Eu ainda precisava "mediar" 10 leituras brutas de rolamentos para suavizar as variações.
Não é o ideal; Isso pode quebrar. Eu me safei nesse caso porque o dispositivo gira apenas muito lentamente. Vou divulgá-lo caso alguém mais se veja trabalhando sob restrições semelhantes.
fonte
Em inglês:
Em python:
Uma matriz de ângulos NX1 #numpy
fonte
Aqui está a solução completa: (a entrada é uma matriz de rolamentos em graus (0-360)
fonte
Em python, com ângulos entre [-180, 180)
Detalhes:
Para a média de dois ângulos existem duas médias separadas por 180 °, mas podemos querer a média mais próxima.
Visualmente, a média do azul ( b ) e verde ( a ) produz o ponto verde-azulado:
Os ângulos 'envolvem' (por exemplo, 355 + 10 = 5), mas a aritmética padrão ignorará esse ponto de ramificação. No entanto, se o ângulo b for oposto ao ponto de ramificação, então ( b + g ) / 2 fornece a média mais próxima: o ponto de cerceta.
Para quaisquer dois ângulos, podemos rotacionar o problema para que um dos ângulos fique oposto ao ponto de ramificação, faça a média padrão e depois gire para trás.
fonte
Eu seguiria o caminho do vetor usando números complexos. Meu exemplo está no Python, que possui números complexos internos:
Observe que o Python não precisa criar uma nova lista temporária de vetores; tudo isso pode ser feito em uma única etapa; Eu apenas escolhi esse caminho para aproximar o pseudo-código aplicável a outros idiomas também.
fonte
Aqui está uma solução completa em C ++:
Ele pega os ângulos na forma de um vetor de duplas e retorna a média simplesmente como um duplo. Os ângulos devem estar em graus e, é claro, a média também está em graus.
fonte
avgCos
é a média dos componentes x eavgSin
é a média dos componentes y. Os parâmetros para a função arco tangente sãoatan2( y, x )
. Portanto, seu código não deveria ser:atan2( avgSin, avgCos )
??Com base na resposta de Alnitak , escrevi um método Java para calcular a média de vários ângulos:
Se seus ângulos estão em radianos:
Se seus ângulos estão em graus:
fonte
Aqui está uma idéia: construa a média iterativamente, sempre calculando a média dos ângulos mais próximos, mantendo um peso.
Outra idéia: encontre o maior espaço entre os ângulos dados. Encontre o ponto que o divide e, em seguida, escolha o ponto oposto no círculo como o zero de referência para calcular a média.
fonte
Vamos representar esses ângulos com pontos na circunferência do círculo.
Podemos assumir que todos esses pontos caem na mesma metade do círculo? (Caso contrário, não há uma maneira óbvia de definir o "ângulo médio". Pense em dois pontos no diâmetro, por exemplo, 0 graus e 180 graus --- é a média de 90 graus ou 270 graus? O que acontece quando temos 3 ou mais distribuir uniformemente pontos?)
Com essa suposição, escolhemos um ponto arbitrário nesse semicírculo como a "origem" e medimos o conjunto de ângulos especificado em relação a essa origem (chamamos isso de "ângulo relativo"). Observe que o ângulo relativo tem um valor absoluto estritamente menor que 180 graus. Por fim, calcule a média desses ângulos relativos para obter o ângulo médio desejado (em relação à nossa origem, é claro).
fonte
Não existe uma única "resposta certa". Eu recomendo a leitura do livro, KV Mardia e PE Jupp, "Directional Statistics", (Wiley, 1999), para uma análise completa.
fonte
(Apenas quero compartilhar meu ponto de vista da teoria da estimativa ou inferência estatística)
O julgamento de Nimble é obter a estimativa MMSE ^ de um conjunto de ângulos, mas é uma das opções encontrar uma direção "média"; também é possível encontrar uma estimativa MMAE ^, ou alguma outra estimativa como a direção "média", e isso depende do seu erro de direção de quantificação métrica; ou, mais geralmente, na teoria das estimativas, a definição da função de custo.
^ MMSE / MMAE corresponde ao erro médio quadrático / absoluto mínimo.
ackb disse "O ângulo médio phi_avg deve ter a propriedade que sum_i | phi_avg-phi_i | ^ 2 se torna mínima ... eles calculam a média de algo, mas não de ângulos"
---- você quantifica erros no sentido quadrático médio e é uma das maneiras mais comuns, no entanto, não é a única. A resposta favorecida pela maioria das pessoas aqui (ou seja, soma dos vetores unitários e obter o ângulo do resultado) é na verdade uma das soluções razoáveis. É (pode ser provado) o estimador de ML que serve como a direção "média" que queremos, se as direções dos vetores forem modeladas como distribuição de von Mises. Essa distribuição não é sofisticada e é apenas uma distribuição periodicamente amostrada de um guassiano 2D. Veja Eqn. (2.179) no livro de Bishop "Reconhecimento de padrões e aprendizado de máquina". Novamente, de modo algum é o único melhor para representar a direção "média", no entanto, é bastante razoável que tenha boa justificativa teórica e implementação simples.
Nimble disse que "a ackb está certa de que essas soluções baseadas em vetores não podem ser consideradas médias reais de ângulos, elas são apenas uma média das contrapartes em vetores unitários"
----isso não é verdade. O "vetor unitário equivalente" revela as informações da direção de um vetor. O ângulo é uma quantidade sem considerar o comprimento do vetor, e o vetor unitário é algo com informações adicionais de que o comprimento é 1. Você pode definir o vetor "unitário" como sendo o comprimento 2, isso realmente não importa.
fonte
Aqui está uma solução completamente aritmética usando médias móveis e tomando o cuidado de normalizar valores. É rápido e fornece respostas corretas se todos os ângulos estiverem em um lado do círculo (a 180 ° um do outro).
É matematicamente equivalente a adicionar o deslocamento que altera os valores para o intervalo (0, 180), calcular a média e subtrair o deslocamento.
Os comentários descrevem qual intervalo um valor específico pode assumir a qualquer momento
fonte
Bem, estou muito atrasado para a festa, mas pensei em adicionar meus 2 centavos, pois não consegui encontrar nenhuma resposta definitiva. No final, implementei a seguinte versão Java do método Mitsuta que, espero, forneça uma solução simples e robusta. Especialmente porque o desvio padrão fornece uma dispersão de medida e, se sd == 90, indica que os ângulos de entrada resultam em uma média ambígua.
Edição: Na verdade, percebi que minha implementação original pode ser ainda mais simplificada, de fato preocupantemente simples, considerando toda a conversa e trigonometria acontecendo nas outras respostas.
... e para todos os seus geeks (Java), você pode usar a abordagem acima para obter o ângulo médio em uma linha.
fonte
Alnitak tem a solução certa. A solução de Nick Fortescue é funcionalmente a mesma.
Para o caso especial de onde
(soma (x_componente) = 0,0 && soma (y_componente) = 0,0) // por exemplo, 2 ângulos de 10. e 190. graus ea.
use 0,0 graus como a soma
Computacionalmente, você deve testar esse caso, pois atan2 (0, 0) é indefinido e gera um erro.
fonte
O ângulo médio phi_avg deve ter a propriedade que sum_i | phi_avg-phi_i | ^ 2 se torna mínima, onde a diferença deve estar em [-Pi, Pi) (porque pode ser mais curto para o contrário!). Isso é facilmente alcançado normalizando todos os valores de entrada para [0, 2Pi), mantendo um phi_run médio em execução e escolhendo normalizando | phi_i-phi_run | para [-Pi, Pi) (adicionando ou subtraindo 2Pi). A maioria das sugestões acima faz outra coisa que não tem essa propriedade mínima, ou seja, elas têm uma média de alguma coisa , mas não ângulos.
fonte
Resolvi o problema com a ajuda da resposta de @David_Hanak. Como ele afirma:
Então, o que eu fiz foi calcular a média de todos os ângulos. E então todos os ângulos menores que isso, aumentam em 360. Em seguida, recalcule a média adicionando todos eles e dividindo-os pelo comprimento.
Funciona perfeitamente.
fonte
Função Python:
fonte
Você pode usar esta função no Matlab:
fonte
Você pode ver uma solução e uma pequena explicação no link a seguir, para QUALQUER linguagem de programação: https://rosettacode.org/wiki/Averages/Mean_angle
Por exemplo, solução C ++ :
Resultado:
Ou solução Matlab :
fonte
Enquanto a resposta do starblue fornece o ângulo do vetor unitário médio, é possível estender o conceito da média aritmética para ângulos se você aceitar que pode haver mais de uma resposta no intervalo de 0 a 2 * pi (ou 0 ° a 360 °). Por exemplo, a média de 0 ° e 180 ° pode ser 90 ° ou 270 °.
A média aritmética tem a propriedade de ser o valor único com a soma mínima de distâncias ao quadrado dos valores de entrada. A distância ao longo do círculo unitário entre dois vetores unitários pode ser facilmente calculada como o cosseno inverso do seu produto escalar. Se escolhermos um vetor unitário minimizando a soma do cosseno inverso ao quadrado do produto escalar de nosso vetor e cada vetor unitário de entrada, teremos uma média equivalente. Novamente, lembre-se de que pode haver dois ou mais mínimos em casos excepcionais.
Esse conceito pode ser estendido a qualquer número de dimensões, uma vez que a distância ao longo da esfera unitária pode ser calculada exatamente da mesma maneira que a distância ao longo do círculo unitário - o cosseno inverso do produto escalar de dois vetores unitários.
Para círculos, poderíamos resolver essa média de várias maneiras, mas proponho o seguinte algoritmo O (n ^ 2) (os ângulos estão em radianos e evito calcular os vetores unitários):
Se todos os ângulos estiverem a 180 ° um do outro, poderíamos usar um algoritmo O (n) + O (classificação) mais simples (novamente usando radianos e evitando o uso de vetores unitários):
Para usar graus, basta substituir pi por 180. Se você planeja usar mais dimensões, provavelmente precisará usar um método iterativo para resolver a média.
fonte
O problema é extremamente simples. 1. Verifique se todos os ângulos estão entre -180 e 180 graus. 2. a Adicione todos os ângulos não negativos, calcule a média e COUNT quantos 2. b.Adicione todos os ângulos negativos, calcule a média e COUNT quantos. 3. Considere a diferença de pos_average menos neg_average Se a diferença for maior que 180, altere a diferença para 360 menos diferença. Caso contrário, basta alterar o sinal da diferença. Observe que a diferença é sempre não negativa. O Average_Angle é igual a pos_average mais diferença vezes o "peso", contagem negativa dividida pela soma da contagem negativa e positiva
fonte
Aqui está um código java para ângulos médios, acho que é razoavelmente robusto.
fonte
Eu tenho um método diferente do @Starblue que fornece respostas "corretas" para alguns dos ângulos dados acima. Por exemplo:
Ele usa uma soma sobre as diferenças entre ângulos consecutivos. O código (no Matlab):
fonte
[-90,90,40]
e[90,-90,40]
; Não acho que uma média não comutativa seja muito útil.