Message Boards Message Boards

1
|
14198 Views
|
9 Replies
|
8 Total Likes
View groups...
Share
Share this post:

Finding peaks and valleys in data

This will probably be trivial to some here, but I am trying to figure a function to find the peaks and valleys in a data sequence. For instance, given the following sequence: a = 10 5 3 6 9 15 13 12 9 15 18 20 19 18 ...

A peak is defined as (a[n] > a[n - 1] and a[n] > a[n + 1])

A valley is defined as (a[n] < a[n - 1] and a[n] < a[n + 1])

The peaks are 15 and 20 at indices 5 and 11 (index base 0)

The valleys are 3 and 9 at indices 2 and 8

I would like the result of the function to be of the form: 0 0 3 0 0 15 0 0 9 0 0 20 0 0 ...

or of the form {3 2} {15 5} {9 8} {20 11} ... {peak index} {valley index} ....

Basically, an alternating list of peaks and valleys or of valleys and peaks depending on whether we start with a peak or a valley. Those values that are neither peaks nor valleys are set to 0 in the result.

Or a list of pairs of the form {peak index} or {valley index}

POSTED BY: Henrick Jeanty
9 Replies

I think that Paul Wellin's recent book "Programming with Mathematica®: An Introduction" is quite good. Paul was the head of training at Wolfram Research for many years. The book is for Mathematica 9: it came out a year before version 10 came out, so the new things from version 10 are (obviously!) not discussed.

http://www.amazon.com/Programming-Mathematica-Introduction-Paul-Wellin/dp/1107009464

Nancy Blachman's book is quite good too but it is 13 years old and Mathematica had grown very considerably since then.

POSTED BY: David Reiss

Hello David, Thank you for the pointer. I checked the book out of my school's library. It is in e-book format. I will be reading and looking forward to improving my Mathematica programming knowledge and skills.

Regards, Henrick

POSTED BY: Henrick Jeanty

Hello David,

Thank you for the clarification. Your suggestion is strangely reassuring. "Search documentation for keywords". I feel less like I am somehow being dense for not simply grasping it. Good, I shall search the documentation. I guess that I am wired more towards understanding a small set of simple commands which get combined to make a program (procedural), rather than a large set of powerful commands that can almost be whole programs in their own right.

This brings interesting questions on how do we learn? Are others in this community like me? Or is it just that I have been "programmed" to be more comfortable with the procedural approach thanks to having started with Fortran, then Basic, Assembler, C, C++, C#. Are there people in this community who find Mathematica "obvious" and "natural" to use?

I wonder if anyone in this community has a book to recommend. I have "Mathematica, a practical approach", 2nd Ed, by Nancy Bachman and Colin P. Williams. I will of course be looking at the ample documentation in Mathematica, but I like having a book I can hold in my hands (I guess I'm old fashioned).

Well, thank you for listening to my musings, Henrick

POSTED BY: Henrick Jeanty

Dear Henrick,

David's advice is what most people including me do - search documentation for keywords. You can even search them for functional syntax such as /@ if you unsure about it.

All discussions on this forum are public and everyone can read them. People participating on discussions get an email when the discussion gets any update. So do not worry about CC.

Welcome to Wolfram Community!

~ Vitaliy

POSTED BY: Vitaliy Kaurov

Hi Henrick,

Dont worry. I got CC'd on both of your replies!

By the way, I would have given you the answer that Vitaliy gave you but I forgot about FindPeaks as it is a new function in version 10.

The Documentation Center for Mathematica is actually quite helpful. If you type "find peak" into its search bar, the second and third result that it returns are PeakDetect and FindPeaks. So searching in the documentation is one thing to often try first if you are wondering if Mathematica has a built in functionality that addresses a problem you are working on.

Best regards, David

POSTED BY: David Reiss

Check out functions FindPeaks and PeakDetect.

testList = {10, 5, 3, 6, 9, 15, 13, 12, 9, 15, 18, 20, 19, 18};
peaks = FindPeaks[testList];
valleys = {1, -1} # & /@ FindPeaks[-testList];
ListLinePlot[testList, Epilog -> {Red, PointSize[0.03], Point[peaks], Point[valleys]}]

enter image description here

POSTED BY: Vitaliy Kaurov

Dear Vitaliy, Thank you very much! This is just what I needed. My problem is that I was not aware of the existence of the FindPeaks function, so of course I was trying to figure out how to do this in a functional way. And I just could not figure out how. The strange thing, at least to me, is that I can figure out how to implement the algorithm in 5 seconds if I need to get it done in C++ or in C#. I can then write it out in 30 seconds. THAT is what makes learning Mathematica so frustrating to me. Mathematica is the MOST POWERFUL programming language I know, but figuring out how to do things can be a long trek. There are so many functions available out there, one of which probably being EXACTLY the one you need, but unknown to you unless you read about all the functions and go "Oh, My God! Here is the function I need". But thank you very much. This is what I needed. I will still have to look at "valleys = {1, -1} # & /@ FindPeaks[-testList];" to see what it does. I can see that it multiplies the list by -1 in order to turn valleys into peaks. I am not sure what "{1, -1} # & /@" does to the result. But will look at it.

Something else. I also received an answer from David Reiss. Here it is: In[1]:= testList = {10, 5, 3, 6, 9, 15, 13, 12, 9, 15, 18, 20, 19, 18};

In[2]:= peakTrippleQ[{x, y, z_}] := TrueQ[x < y > z]

In[3]:= peakPositions[list_List] := Flatten[Position[peakTrippleQ /@ Partition[list, 3, 1], True] + 1]

In[4]:= valleyTrippleQ[{x, y, z_}] := TrueQ[x > y < z]

In[5]:= valleyPositions[list_List] := Flatten[Position[valleyTrippleQ /@ Partition[list, 3, 1], True] + 1]

In[6]:= peakPositions[testList]

Out[6]= {6, 12}

In[7]:= valleyPositions[testList]

Out[7]= {3, 9} I am grateful to him too. However, his answer was, at least to me, incomprehensible (and I am not blaming him). My point is how 2 knowledgeable people can come up with 2 such different answers. One incomprehensible (and not doing quite what I need) and one almost totally clear. It makes you wonder, as a novice, how am I supposed to do this efficiently? I could use the procedural approach, but I know (based on a Wolfram Alpha Video I viewed) that the preferred, and most time efficient way, is to use the functional approach.

So, I have a couple of questions for you Vitaliy. How long have you been writing code in Mathematica? Do you write in one of the other Procedural or Object-Oriented Languages like C++? How did you know about FindPeak? Did you just happen to read some book on Mathematica and saw that there is such a function? I am just curious to see how others learn this extremely powerful language, yet, in my view, difficult language to get one's mind wrapped around.

Again, Thank you very much for your answer Vitaliy, Regards, Henrick

P.S. Is there a way to CC: someone when replying? I would have liked to CC: David on this response.

POSTED BY: Henrick Jeanty

First a very quick comment: indices are referenced to 1 rather than 0 in Mathematica.

That said, here is an approach to finding the indices (positions in the list of data) where the peaks or valleys are located

In[1]:= testList = {10, 5, 3, 6, 9, 15, 13, 12, 9, 15, 18, 20, 19, 18};

In[2]:= peakTrippleQ[{x_, y_, z_}] := TrueQ[x < y > z]

In[3]:= peakPositions[list_List] := 
 Flatten[Position[peakTrippleQ /@ Partition[list, 3, 1], True] + 1]

In[4]:= valleyTrippleQ[{x_, y_, z_}] := TrueQ[x > y < z]

In[5]:= valleyPositions[list_List] := 
 Flatten[Position[valleyTrippleQ /@ Partition[list, 3, 1], True] + 1]

In[6]:= peakPositions[testList]

Out[6]= {6, 12}

In[7]:= valleyPositions[testList]

Out[7]= {3, 9}
POSTED BY: David Reiss

Thank you very much for your answer David,
I would have to analyze your answer to understand what each part is doing. However, I must let you know that I received another answer by Vitaliy Kaurov, and it was exactly what I wanted and, I must say, simpler. Here it is: testList = {10, 5, 3, 6, 9, 15, 13, 12, 9, 15, 18, 20, 19, 18}; peaks = FindPeaks[testList]; valleys = {1, -1} # & /@ FindPeaks[-testList]; ListLinePlot[testList, Epilog -> {Red, PointSize[0.03], Point[peaks], Point[valleys]}]

The answer is also in the format I need which is the index of that peak and the peak value. But thank you very much nonetheless. Regards, Henrick

POSTED BY: Henrick Jeanty
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract