Я хочу рассчитать среднее значение для набора циклических данных. Например, у меня может быть несколько образцов из чтения компаса. Проблема, конечно же, заключается в том, как бороться с циклом. Тот же алгоритм может быть полезен для циферблата.
Фактический вопрос более сложен - что означает статистика на сфере или в алгебраическом пространстве, которое «оборачивается», например, аддитивная группа mod n. Ответ может быть не уникальным, например, среднее значение 359 градусов и 1 градус может быть 0 или 180, но статистически 0 выглядит лучше.
Для меня это настоящая проблема программирования, и я пытаюсь сделать так, чтобы она не выглядела просто математической.
Ответы:
Вычислить единичные векторы по углам и взять угол их среднего.
источник
Этот вопрос подробно рассматривается в книге «Статистика по сферам», Джеффри С. Уотсон, Лекционные заметки по математическим наукам Университета Арканзаса, 1983 г., John Wiley & Sons, Inc., как упомянуто по адресу http: //catless.ncl. ac.uk/Risks/7.44.html#subj4 Брюса Карша.
Хороший способ оценить средний угол A из набора угловых измерений a [i] 0 <= i
Метод, данный starblue, эквивалентен в вычислительном отношении, но его причины яснее и, вероятно, программно более эффективны, а также хорошо работают в нулевом случае, так что слава ему.
Теперь предмет более подробно рассматривается в Википедии , а также в других областях, таких как дробные части.
источник
Я вижу проблему - например, если у вас угол 45 'и угол 315', «естественное» среднее значение будет 180 ', но на самом деле вы хотите получить значение 0'.
Я думаю, что Starblue на что-то. Просто вычислите (x, y) декартовы координаты для каждого угла и сложите полученные векторы вместе. Угловое смещение конечного вектора должно быть вашим требуемым результатом.
Сейчас я игнорирую, что направление по компасу начинается с севера и идет по часовой стрелке, тогда как «нормальные» декартовы координаты начинаются с нуля вдоль оси X, а затем идут против часовой стрелки. Математика должна работать одинаково независимо.
источник
cos()
,sin()
иatan2()
дает приближению (хорошее, но все равно от 1 или 2 ulps) , поэтому чем больше вы в среднем, тем больше ошибок вы включите.ПО ОСОБЕННОМУ СЛУЧАЮ ДВУХ УГЛОВ:
Ответ ((а + б) мод 360) / 2 является НЕПРАВИЛЬНО . Для углов 350 и 2 ближайшая точка - 356, а не 176.
Единичный вектор и триггерные решения могут быть слишком дорогими.
Что я получил от небольшого переделывания:
источник
Акб прав, что эти векторные решения нельзя считать истинными средними значениями углов, они являются только средним значением единичных векторов. Тем не менее, предложенное решение Акба не кажется математически обоснованным.
Ниже приведено решение, которое математически получено из цели минимизации (angle [i] - avgAngle) ^ 2 (где разница корректируется при необходимости), что делает его истинным средним арифметическим углов.
Во-первых, нам нужно посмотреть, в каких именно случаях разница между углами отличается от разницы между их обычными числами. Рассмотрим углы x и y, если y> = x - 180 и y <= x + 180, то мы можем напрямую использовать разность (xy). В противном случае, если первое условие не выполняется, мы должны использовать (y + 360) в расчете вместо y. Соответственно, если второе условие не выполнено, тогда мы должны использовать (y-360) вместо y. Поскольку в уравнении кривой мы минимизируем только изменения в точках, где эти неравенства изменяются с истинного на ложное или наоборот, мы можем разделить полный диапазон [0,360) на набор сегментов, разделенных этими точками. Затем нам нужно только найти минимум каждого из этих сегментов, а затем минимум каждого сегмента, который является средним.
Вот изображение, демонстрирующее, где возникают проблемы при расчете угловых разностей. Если х лежит в серой области, тогда возникнет проблема.
Чтобы минимизировать переменную, в зависимости от кривой, мы можем взять производную того, что мы хотим минимизировать, и затем мы найдем точку поворота (где производная = 0).
Здесь мы применим идею минимизации квадрата разности для получения общей средней арифметической формулы: сумма (a [i]) / n. Кривая y = sum ((a [i] -x) ^ 2) может быть минимизирована следующим образом:
Теперь примените его к кривым с нашими скорректированными отличиями:
b = подмножество a, где правильная (угловая) разница a [i] -xc = подмножество a, где правильная (угловая) разница (a [i] -360) -x cn = размер cd = подмножество a, где правильная (угловая) разница (a [i] +360) -x dn = размер d
Одного этого недостаточно для получения минимума, в то время как он работает для нормальных значений, у которых есть неограниченный набор, поэтому результат определенно будет лежать в пределах диапазона набора и, следовательно, действителен. Нам нужен минимум в пределах диапазона (определяемого сегментом). Если минимум меньше нижней границы нашего сегмента, то минимум этого сегмента должен быть на нижней границе (поскольку у квадратичных кривых есть только одна точка поворота), а если минимум больше верхней границы нашего сегмента, то минимум сегмента находится на верхняя граница. После того, как у нас есть минимум для каждого сегмента, мы просто находим тот, который имеет наименьшее значение для того, что мы минимизируем (sum ((b [i] -x) ^ 2) + sum (((c [i] -360 ) -b) ^ 2) + сумма (((d [i] +360) -c) ^ 2)).
Вот изображение кривой, которая показывает, как она изменяется в точках, где x = (a [i] +180)% 360. Набор данных находится под вопросом {65,92,230,320,250}.
Вот реализация алгоритма на Java, включающая некоторые оптимизации, его сложность составляет O (nlogn). Его можно уменьшить до O (n), если заменить сортировку на основе сравнения на сортировку, не основанную на сравнении, такую как сортировка по основанию.
Среднее арифметическое набора углов может не совпадать с вашим интуитивным представлением о том, каким должно быть среднее значение. Например, среднее арифметическое для набора {179,179,0,181,181} равно 216 (и 144). Ответ, о котором вы сразу подумаете, вероятно, равен 180, однако хорошо известно, что среднее арифметическое сильно зависит от значений ребер. Вы также должны помнить, что углы не являются векторами, как это может показаться привлекательным, когда иногда приходится иметь дело с углами.
Этот алгоритм, конечно, также применим ко всем величинам, которые подчиняются модульной арифметике (с минимальной корректировкой), например, ко времени суток.
Я также хотел бы подчеркнуть, что, хотя это истинное среднее углов, в отличие от векторных решений, это не обязательно означает, что это решение, которое вы должны использовать, среднее значение соответствующих единичных векторов вполне может быть значением, которое вы на самом деле следует использовать.
источник
Вы должны определить среднее значение более точно. Для конкретного случая двух углов я могу представить два разных сценария:
Однако я не понимаю, как можно обобщить вторую альтернативу на случай более двух углов.
источник
Как и все средние, ответ зависит от выбора метрики. Для данной метрики M среднее значение некоторых углов a_k в [-pi, pi] для k в [1, N] является тем углом a_M, который минимизирует сумму квадратов расстояний d ^ 2_M (a_M, a_k). Для взвешенного среднего можно просто включить в сумму веса w_k (такие, что sum_k w_k = 1). То есть,
a_M = arg min_x sum_k w_k d ^ 2_M (x, a_k)
Два общих выбора метрики - это метрики Фробениуса и Римана. Для метрики Фробениуса существует прямая формула, которая соответствует обычному понятию среднего значения в круговой статистике. См. «Средства и усреднение в группе ротаций», Maher Moakher, SIAM Journal по матричному анализу и приложениям, том 24, выпуск 1, 2002, для получения более подробной информации.
http://link.aip.org/link/?SJMAEL/24/1/1
Вот функция для GNU Octave 3.2.4, которая выполняет вычисления:
источник
Я хотел бы поделиться методом, который я использовал с микроконтроллером, который не имел возможностей с плавающей запятой или тригонометрии. Мне все еще нужно было «усреднить» 10 необработанных показаний подшипников, чтобы сгладить вариации.
Это не идеально; это может сломаться. В этом случае мне это сошло с рук, потому что устройство вращается очень медленно. Я опубликую это на тот случай, если кто-то окажется, что работает в подобных условиях.
источник
По-английски:
В питоне:
#Numpy NX1 массив углов
источник
Вот полное решение: (входной сигнал представляет собой массив азимутов в градусах (0-360)
источник
В питоне, с углами между [-180, 180)
Подробности:
Для среднего из двух углов есть два средних между 180 °, но мы можем хотеть более близкое среднее.
Визуально, среднее значение синего ( b ) и зеленого ( a ) значений дает точку размытия:
Углы «окружают» (например, 355 + 10 = 5), но стандартная арифметика игнорирует эту точку ветвления. Однако, если угол b противоположен точке ветвления, то ( b + g ) / 2 дает ближайший средний показатель: чирокую точку.
Для любых двух углов мы можем повернуть задачу так, чтобы один из углов был противоположен точке ветвления, выполнить стандартное усреднение, а затем повернуть назад.
источник
Я бы пошел вектор, используя комплексные числа. Мой пример в Python, который имеет встроенные комплексные числа:
Обратите внимание, что Python не должен создавать временный новый список векторов, все вышеперечисленное можно сделать за один шаг; Я просто выбрал этот способ, чтобы приблизить псевдокод, применимый и к другим языкам.
источник
Вот полное решение C ++:
Он принимает углы в виде вектора двойных значений и возвращает среднее значение просто как двойной. Углы должны быть в градусах, и, конечно, среднее значение также в градусах.
источник
avgCos
является средним из компонентов х, иavgSin
является средним из компонентов у. Параметры для функции арктангенса являютсяatan2( y, x )
. Итак, не должен ли ваш код:atan2( avgSin, avgCos )
??Основываясь на ответе Алнитак , я написал метод Java для вычисления среднего значения нескольких углов:
Если ваши углы в радианах:
Если ваши углы в градусах:
источник
Вот идея: построить среднее значение итеративно, всегда вычисляя среднее из углов, которые находятся ближе всего друг к другу, сохраняя вес.
Другая идея: найти самый большой зазор между заданными углами. Найдите точку, которая делит ее пополам, а затем выберите противоположную точку на круге в качестве контрольного нуля, чтобы вычислить среднее значение.
источник
Представим эти углы точками на окружности круга.
Можно ли предположить, что все эти точки попадают на одну и ту же половину круга? (В противном случае, нет очевидного способа определить «средний угол». Подумайте о двух точках на диаметре, например, 0 и 180 градусов - это в среднем 90 или 270 градусов? Что происходит, когда у нас есть 3 или более равномерно распределить точки?)
С этим предположением мы выбираем произвольную точку на этом полукруге в качестве «начала координат» и измеряем заданный набор углов относительно этого начала координат (назовем это «относительным углом»). Обратите внимание, что относительный угол имеет абсолютное значение строго менее 180 градусов. Наконец, возьмите среднее значение этих относительных углов, чтобы получить желаемый средний угол (относительно нашего происхождения, конечно).
источник
Там нет ни одного "правильного ответа". Я рекомендую прочитать книгу KV Mardia и PE Jupp, "Direction Statistics" (Wiley, 1999), для тщательного анализа.
источник
(Просто хочу поделиться своей точкой зрения из теории оценивания или статистического вывода)
Задача Nimble состоит в том, чтобы получить оценку MMSE ^ для набора углов, но это один из вариантов поиска «усредненного» направления; Можно также найти оценку MMAE ^ или некоторую другую оценку, чтобы быть «усредненным» направлением, и это зависит от вашей количественной погрешности измерения метрики направления; или, в более общем смысле, в теории оценки - определение функции стоимости.
^ MMSE / MMAE соответствует минимальному среднему квадрату / абсолютной ошибке.
Акб сказал: «Средний угол phi_avg должен иметь свойство, которое sum_i | phi_avg-phi_i | ^ 2 становится минимальным ... они что-то усредняют, но не углы»
---- вы определяете количество ошибок в среднеквадратичном смысле, и это один из наиболее распространенных способов, однако не единственный. Ответ, одобренный большинством людей здесь (т. Е. Сумма векторов единиц и получение угла результата), на самом деле является одним из разумных решений. Это (может быть доказано) оценка ML, которая служит «усредненным» направлением, которое мы хотим, если направления векторов моделируются как распределение фон Мизеса. Это распределение не является причудливым и представляет собой просто периодически выбираемое распределение из двумерного гассиана. Смотрите уравнение (2.179) в книге Бишопа «Распознавание образов и машинное обучение». Опять же, ни в коем случае это не единственный лучший способ представить «среднее» направление, однако это вполне разумный вариант, имеющий хорошее теоретическое обоснование и простую реализацию.
Нимбл сказал: «Акб прав, что эти векторные решения нельзя считать истинными средними значениями углов, они являются только средними значениями единичных векторов».
----это неправда. «Единичные векторные аналоги» раскрывают информацию о направлении вектора. Угол - это величина без учета длины вектора, а единичный вектор - это нечто с дополнительной информацией о том, что длина равна 1. Вы можете определить, что ваш «единичный» вектор имеет длину 2, это на самом деле не имеет значения.
источник
Вот полностью арифметическое решение с использованием скользящих средних и заботой о нормализации значений. Это быстро и дает правильные ответы, если все углы находятся на одной стороне круга (в пределах 180 ° друг от друга).
Это математически эквивалентно добавлению смещения, которое сдвигает значения в диапазон (0, 180), вычисляет среднее значение и затем вычитает смещение.
Комментарии описывают, какой диапазон может принимать конкретное значение в любой момент времени.
источник
Ну, я очень опоздал на вечеринку, но подумал, что добавлю свои 2 цента, потому что я не смог найти окончательного ответа. В конце я реализовал следующую Java-версию метода Mitsuta, которая, я надеюсь, обеспечивает простое и надежное решение. В частности, стандартное отклонение обеспечивает как дисперсию измерения, так и, если sd == 90, указывает, что входные углы приводят к неоднозначному среднему значению.
РЕДАКТИРОВАТЬ: На самом деле я понял, что моя первоначальная реализация может быть еще более упрощена, на самом деле, на удивление просто, учитывая все разговоры и тригонометрию, происходящие в других ответах.
... и для всех вас (Java) гиков, вы можете использовать вышеупомянутый подход, чтобы получить средний угол в одной строке.
источник
Альнитак имеет правильное решение. Решение Ника Фортескью функционально одинаково.
Для особого случая, где
(sum (x_component) = 0.0 && sum (y_component) = 0.0) // например, 2 угла 10 и 190. градусов.
используйте 0,0 градусов в качестве суммы
В вычислительном отношении вы должны проверить этот случай, так как atan2 (0, 0) не определено и приведет к ошибке.
источник
Средний угол phi_avg должен обладать свойством того, что sum_i | phi_avg-phi_i | ^ 2 становится минимальным, где разница должна быть в [-Pi, Pi) (потому что это может быть короче, если будет наоборот!). Это легко достигается путем нормализации всех входных значений до [0, 2Pi), сохранения среднего значения phi_run и выбора нормализации | phi_i-phi_run | к [-Pi, Pi) (путем добавления или вычитания 2Pi). Большинство предложений выше делают что-то еще, что не имеет этого минимального свойства, то есть они усредняют что-то , но не углы.
источник
Я решил проблему с помощью ответа от @David_Hanak. Как он заявляет:
Поэтому я вычислил среднее значение по всем углам. И затем все углы, которые меньше этого, увеличивают их на 360. Затем пересчитайте среднее значение, сложив их все и разделив на их длину.
Работает отлично.
источник
Функция Python:
источник
Вы можете использовать эту функцию в Matlab:
источник
Вы можете увидеть решение и небольшое объяснение в следующей ссылке для ЛЮБОГО языка программирования: https://rosettacode.org/wiki/Averages/Mean_angle
Например, решение C ++ :
Вывод:
Или решение Matlab :
источник
В то время как ответ starblue дает угол среднего единичного вектора, можно расширить понятие среднего арифметического на углы, если принять, что может быть более одного ответа в диапазоне от 0 до 2 * пи (или от 0 ° до 360 °). Например, среднее значение 0 ° и 180 ° может составлять либо 90 °, либо 270 °.
Среднее арифметическое имеет свойство быть единственным значением с минимальной суммой квадратов расстояний до входных значений. Расстояние вдоль единичного круга между двумя единичными векторами можно легко рассчитать как обратный косинус их точечного произведения. Если мы выберем единичный вектор путем минимизации суммы квадрата обратного косинуса точечного произведения нашего вектора и каждого входного единичного вектора, то мы получим эквивалентное среднее значение. Опять же, имейте в виду, что в исключительных случаях может быть два или более минимума.
Эту концепцию можно распространить на любое количество измерений, поскольку расстояние вдоль единичной сферы можно рассчитать точно так же, как расстояние вдоль единичной окружности - обратный косинус точечного произведения двух единичных векторов.
Для кругов мы могли бы решить для этого среднего значения несколькими способами, но я предлагаю следующий алгоритм O (n ^ 2) (углы указаны в радианах, и я избегаю вычисления единичных векторов):
Если все углы находятся в пределах 180 ° друг от друга, то мы могли бы использовать более простой алгоритм O (n) + O (sort) (снова используя радианы и избегая использования единичных векторов):
Чтобы использовать градусы, просто замените pi на 180. Если вы планируете использовать больше измерений, вам, скорее всего, придется использовать итерационный метод для вычисления среднего значения.
источник
Проблема чрезвычайно проста. 1. Убедитесь, что все углы находятся в диапазоне от -180 до 180 градусов. 2. a Добавьте все неотрицательные углы, возьмите их среднее и СЧИТАЙТЕ сколько 2. б. Добавьте все отрицательные углы, возьмите их среднее и СЧИТАЙТЕ сколько. 3. Возьмите разницу pos_average минус neg_average. Если разница больше 180, то измените разницу на 360 минус разница. В противном случае просто измените знак различия. Обратите внимание, что разница всегда неотрицательна. Average_Angle равен pos_average плюс разница, умноженная на «вес», отрицательное число, деленное на сумму отрицательного и положительного числа
источник
Вот немного кода Java для усреднения углов, я думаю, что он достаточно надежный.
источник
У меня есть метод, отличный от @Starblue, который дает «правильные» ответы на некоторые из приведенных выше углов. Например:
Он использует сумму по разнице между последовательными углами. Код (в Matlab):
источник
[-90,90,40]
и[90,-90,40]
; Я не думаю, что некоммутативное среднее очень полезно.