Якщо у мене є набір даних, який створює такий графік, як наведено нижче, я б алгоритмічно визначити значення x показаних піків (у цьому випадку їх три):
Якщо у мене є набір даних, який створює такий графік, як наведено нижче, я б алгоритмічно визначити значення x показаних піків (у цьому випадку їх три):
Відповіді:
Загальний підхід полягає в згладжуванні даних, а потім пошуку піків шляхом порівняння локального максимального фільтра з гладким . В R
:
argmax <- function(x, y, w=1, ...) {
require(zoo)
n <- length(y)
y.smooth <- loess(y ~ x, ...)$fitted
y.max <- rollapply(zoo(y.smooth), 2*w+1, max, align="center")
delta <- y.max - y.smooth[-c(1:w, n+1-1:w)]
i.max <- which(delta <= 0) + w
list(x=x[i.max], i=i.max, y.hat=y.smooth)
}
Його повернене значення включає аргументи локальних максимумів ( x
) - це відповідає на питання - та індексує у масиви x- та y, де трапляються ці локальні максимуми ( i
).
Є два параметри, які слід налаштовувати на обставини: w
це половина ширини вікна, що використовується для обчислення локального максимуму. (Його значення повинно бути значно менше половини довжини масиву даних.) Невеликі значення дозволять назбирати крихітні локальні удари, тоді як більші значення перейдуть прямо над ними. Ще один - не явний в цьому коді - span
аргумент loess
більш плавного. (Зазвичай це між нулем і одиницею; він відображає ширину вікна як пропорцію діапазону значень x.) Більші значення згладжують дані більш агресивно, змушуючи локальні удари зникати зовсім.
Щоб побачити цю настройку по суті, давайте створимо невелику тестову функцію для побудови результатів:
test <- function(w, span) {
peaks <- argmax(x, y, w=w, span=span)
plot(x, y, cex=0.75, col="Gray", main=paste("w = ", w, ", span = ", span, sep=""))
lines(x, peaks$y.hat, lwd=2) #$
y.min <- min(y)
sapply(peaks$i, function(i) lines(c(x[i],x[i]), c(y.min, peaks$y.hat[i]),
col="Red", lty=2))
points(x[peaks$i], peaks$y.hat[peaks$i], col="Red", pch=19, cex=1.25)
}
Ось кілька експериментів, застосованих до деяких синтетичних, трохи шумних даних.
x <- 1:1000 / 100 - 5
y <- exp(abs(x)/20) * sin(2 * x + (x/5)^2) + cos(10*x) / 5 + rnorm(length(x), sd=0.05)
par(mfrow=c(3,1))
test(2, 0.05)
test(30, 0.05)
test(2, 0.2)
Або широке вікно (середня ділянка), або більш агресивна гладка (нижня ділянка) усувають локальні максимуми, виявлені у верхній ділянці. Найкраща комбінація тут, ймовірно, широке вікно і лише м'яке згладжування, оскільки, здається, агресивне згладжування зміщує ці вершини (див. Середину та праву точки нижньої ділянки та порівняння їх розташування з очевидними вершинами вихідних даних). У цьому прикладі w=50
і span=0.05
чудово справляється (не показано).
Зауважте, локальні максимуми в кінцевих точках не виявлені. Їх можна оглянути окремо. (Щоб підтримати це, argmax
повертає згладжені y-значення.)
Цей підхід має ряд переваг перед більш формальним моделюванням для роботи загального призначення:
Він не приймає жодної заздалегідь продуманої моделі даних.
Він може бути адаптований до характеристик даних.
Він може бути адаптований для виявлення видів піків, які вас цікавлять.
w
та span
, а також виявити, що більш високі значення span
зміщували вершини. Схоже, навіть ці кроки можна автоматизувати. Наприклад, для першого питання, якби ми могли оцінити якість виявлених піків, ми могли б працювати optimize
за параметрами! Для другого питання, наприклад, виберіть вікно з будь-якої сторони виявленої вершини та шукайте більш високі значення.
Як я згадував у коментарі, якщо часовий ряд видається періодичним, що відповідає гармонічній регресійній моделі, це спосіб згладити функцію та визначити пік, застосовуючи перший та другий тести на похідні. Юбер вказав на непараметричний тест, який має переваги, коли є кілька піків, і функція не обов'язково періодична. Але безкоштовного обіду немає. Незважаючи на те, що є його переваги в тому, що він зазначає, можуть бути і недоліки, якщо параметрична модель підходить. Це завжди зворотний бік до використання непараметричних прийомів. Хоча це дозволяє уникнути параметричних припущень, параметричний підхід краще, коли параметричні припущення є відповідними. Його процедура також не повністю використовує структуру часових рядів у даних.
Я думаю, що, хоча доречно вказати на переваги запропонованої процедури, важливо також вказати на потенційні недоліки. І мій підхід, і Губер знаходять піки ефективно. Однак я думаю, що його процедура потребує трохи більше роботи, коли локальний максимум нижчий за раніше визначений найвищий пік.
Класичний підхід до виявлення піку в обробці сигналів такий:
Інший підхід, який працює, полягає в порівнянні різко відфільтрованого високошвидкісного сигналу з сильно згладженим (низькопрохідним або серединним відфільтрованим) і застосувати крок 3.
Сподіваюся, це допомагає.