Определите важные минимумы и максимумы во временных рядах с Mathematica - PullRequest
5 голосов
/ 26 января 2011

Мне нужен способ определения локальных минимумов и максимумов в данных временных рядов с помощью Mathematica. Кажется, это должно быть легко, но это сложно. Я разместил это на MathForum, но подумал, что мог бы получить дополнительные сведения здесь.

Вы можете найти статью, в которой обсуждается проблема по адресу: http://www.cs.cmu.edu/~eugene/research/full/compress-series.pdf

Я уже пробовал это ...

Получить и отформатировать некоторые данные:

data = FinancialData["SPY", {"May 1, 2006", "Jan. 21, 2011"}][[All, 2]];
data = data/First@data;
data = Transpose[{Range[Length@data], data}];

Определить 2 функции:

Первый метод:

findMinimaMaxima[data_, window_] := With[{k = window},
  data[[k + Flatten@Position[Partition[data[[All, 2]], 2 k + 1, 1],  x_List /;  x[[k + 1]] < Min[Delete[x, k + 1]] || x[[k + 1]] > Max[Delete[x, k + 1]]]]]]

Теперь другой подход, хотя и не такой гибкий:

findMinimaMaxima2[data_] := data[[Accumulate@(Length[#] & /@ Split[Prepend[Sign[Rest@data[[All, 2]] - Most@data[[All, 2]]], 0]])]]

Посмотрите, что делает каждая функция. Сначала найдите MinimaMaxima2 []:

minmax = findMinimaMaxima2[data];
{Length@data, Length@minmax}
ListLinePlot@minmax

При этом выбираются все минимумы, максимумы и результаты (в данном случае) при сжатии данных примерно на 49%, но он не обладает гибкостью расширения окна. Этот другой метод делает. Окно 2 дает меньше и, возможно, более важные экстремумы:

minmax2 = findMinimaMaxima[data, 2];
{Length@data, Length@minmax2}
ListLinePlot@minmax2

Но посмотрите, что происходит, когда мы расширяем окно до 60:

minmax2 = findMinimaMaxima[data, 60];
ListLinePlot[{data, minmax2}]

Некоторые из минимумов и максимумов больше не чередуются. Применение findMinimaMaxima2 [] к выводу findMinimaMaxima [] дает обходной путь ...

minmax3 = findMinimaMaxima2[minmax2];
ListLinePlot[{data, minmax2, minmax3}]

, но это кажется неуклюжим способом решения проблемы.

Таким образом, идея использовать фиксированное окно для просмотра влево и вправо не совсем то, что хотелось бы. Я начал думать об альтернативе, которая могла бы использовать значение диапазона R (например, процентное движение вверх или вниз), которому функция должна соответствовать или превышать, чтобы установить следующие минимумы или максимумы. Вот моя первая попытка:

findMinimaMaxima3[data_, R_] := Module[{d, n, positions},
  d = data[[All, 2]];
  n = Transpose[{data[[All, 1]], Rest@FoldList[If[(#2 <= #1 + #1*R && #2 >= #1) || (#2 >= #1 - #1* R && #2 <= #1), #1, #2] &, d[[1]], d]}];
  n = Sign[Rest@n[[All, 2]] - Most@n[[All, 2]]];
  positions = Flatten@Rest[Most[Position[n, Except[0]]]];
  data[[positions]]
  ]

minmax4 = findMinimaMaxima3[data, 0.1];
ListLinePlot[{data, minmax4}]

Это также выигрывает от постобработки с findMinimaMaxima2 []

ListLinePlot[{data, findMinimaMaxima2[minmax4]}]

Но если вы посмотрите внимательно, вы увидите, что он пропускает крайности, если они выходят за пределы значения R в нескольких позициях - включая абсолютный минимум и максимум графика, а также вдоль больших движений вверх и вниз. Изменение значения R показывает, как оно пропускает верх и низ еще больше:

minmax4 = findMinimaMaxima3[data, 0.15];
ListLinePlot[{data, minmax4}]

Итак, мне нужно пересмотреть. Любой может посмотреть на график данных и легко определить важные минимумы и максимумы. Кажется, сложнее получить алгоритм для этого. Окно и / или значение R кажутся важными для решения, но ни одного из них не кажется достаточным (по крайней мере, в подходах, описанных выше).

Может ли кто-нибудь расширить какой-либо из показанных подходов или предложить альтернативу идентификации важных минимумов и максимумов?

Рад переслать блокнот со всем этим кодом и обсуждением в нем. Дайте мне знать, если это кому-нибудь нужно.

Спасибо, Jagra

1 Ответ

8 голосов
/ 26 января 2011

Предлагаю использовать итеративный подход.Следующие функции взяты из этого поста , и хотя они могут быть написаны более кратко без компиляции, они будут выполнять эту работу:

localMinPositionsC = 
 Compile[{{pts, _Real, 1}}, 
   Module[{result = Table[0, {Length[pts]}], i = 1, ctr = 0}, 
    For[i = 2, i < Length[pts], i++, 
     If[pts[[i - 1]] > pts[[i]] && pts[[i + 1]] > pts[[i]], 
      result[[++ctr]] = i]];
    Take[result, ctr]]];

localMaxPositionsC = 
  Compile[{{pts, _Real, 1}}, 
    Module[{result = Table[0, {Length[pts]}], i = 1, ctr = 0}, 
      For[i = 2, i < Length[pts], i++, 
        If[pts[[i - 1]] < pts[[i]] && pts[[i + 1]] < pts[[i]], 
          result[[++ctr]] = i]];
       Take[result, ctr]]];

Вот ваш график данных:

dplot = ListLinePlot[data]

Здесь мы строим минуты, которые получаются после 3 итераций:

mins = ListPlot[Nest[#[[localMinPositionsC[#[[All, 2]]]]] &, data, 3],
   PlotStyle -> Directive[PointSize[0.015], Red]]

То же самое для максимумов:

maxs = ListPlot[Nest[#[[localMaxPositionsC[#[[All, 2]]]]] &, data, 3],
   PlotStyle -> Directive[PointSize[0.015], Green]]

И результирующий график:

Show[{dplot, mins, maxs}]

enter image description here

Вы можете варьировать количество итераций, чтобы получить более грубые или более мелкие минимумы / максимумы.

Редактировать:

на самом деле, я только что заметил, что этот метод все еще упускает пару моментов, как для минимумов, так и для максимумов.Итак, я предлагаю это как отправную точку, а не как полное решение.Возможно, вы могли бы проанализировать минимумы / максимумы, поступающие с разных итераций, а иногда и включить те из «предыдущего», более детального.Кроме того, единственная «физическая причина», по которой работает этот вид, заключается в том, что природа финансовых данных выглядит фрактальной, с несколькими отчетливо разными масштабами.Каждая итерация в вышеупомянутых Nest-ов нацелена на определенный масштаб.Это не будет работать так хорошо для произвольного сигнала.

...