Turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

- Home
- /
- Analytics
- /
- Forecasting
- /
- Identify Zigzag point for timeseries

Options

- RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Mute
- Printer Friendly Page

☑ This topic is **solved**.
Need further help from the community? Please
sign in and ask a **new** question.

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

Posted 11-17-2022 04:24 PM
(7392 views)

Hi Everyone,

I want to find the zigzag point for timeseries and quite surprise, there isn't much discussion on this topic.

In the data below, the zigzag point should be number 10, 1 and 10

Can you please help me with the code?

The zigzag line is in picture below

Thanks,

HHC

```
data have;
input value;
datalines;
6
7
8
8
10
9
8
8
8
7
6
8
8
4
5
1
2
3
4
6
6
8
9
10
6
8
6
5
1
;run;
data have; set have;
n=_N_;run;
```

1 ACCEPTED SOLUTION

Accepted Solutions

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

The responses given so far are quite good. I am not aware of any thing in SAS/ETS or (SAS/ECONOMETRICS) that is specifically designed for peak-discovery. I think this problem can also be called identifying turning points of a time series. For noisy time series the interest could be in finding the turning points of the underlying smooth signal. I will describe a quick way of doing this by using PROC UCM in SAS/ETS. Of course, this is a solution to a related problem and not the original one.

Let's say the value_t series can be thought of as a sum of mu_t, a smooth curve, and noise_t: value_t = mu_t + noise_t. The following code shows you how to fit this model when mu_t is modeled by an integrated random walk, which produces cubic smoothing spline, and Gaussian white noise:

proc ucm data=have;

id n interval=obs;

model value;

irregular;

level variance=0 noest;

slope plot=smooth;

forecast lead=0 outfor=for plot=decomp;

run;

The output data set "for" contains the estimates of mu_t and its slope (the columns s_level and s_slope). The turning points of mu_t could be located as places where the sign of adjacent s_level values change (i.e., points where s_level stops going upward/downward). These points are located by the following data steps:

data change;

set for(keep=n value s_level s_slope);

s1 = lag(s_slope);

turn = 0;

if n >= 2 then do;

if sign(s1) ^= sign(s_slope) then turn=1;

end;

run;

*The turns data set contains the discovered turn points: 5 17 24;

data turns;

set change;

where turn=1;

run;

The following plot shows how well s_level approximates the original series:

The following curve plots the slope (s_slope):

The following code shows the discovered turning points:

proc sgplot data=change;

title Plot of smoothed_value with identified turning points;

series x=n y=s_level;

refline 5 17 24/ axis=x;

run;

Of course, the identified turning points are not the turning points of the original series but of the underlying smooth signal. The following plot shows how they appear for the original curve:

proc sgplot data=change;

title Plot of value with identified turning points for smoothed_value;

series x=n y=value;

refline 5 17 24/ axis=x;

run;

I know this is a bit lengthy response.

16 REPLIES 16

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

I added a picture link in my original post.

Thanks,

HHC

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

It does not explain the logic. Please be more specific about your requirements.

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

You want to effectively finds local minima and maxima in a time series. Those local extremes can then be connected to generate a set of zigzag line segments.

But you have to define for us

- what "local" is, i.e. how large a window is required to examine for a change in direction, and
- how large a change in direction must be to designate the local minimum or maximum.

--------------------------

The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for

Allow PROC SORT to output multiple datasets

--------------------------

The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for

Allow PROC SORT to output multiple datasets

--------------------------

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

@mkeintz , you are 100% correct. The thing is for that Zigzag, normally other software have the "local" and "size of change" parameters and user can adjust.

Can you do something like that?

I find it quite weird that I can't find any code for this very popular timeseries measure 😕

Thanks,

HHC

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

calling @Rick_SAS

```
/*Here could give you a start*/
data have;
input value;
n+1;
datalines;
6
7
8
8
10
9
8
8
8
7
6
8
8
4
5
1
2
3
4
6
6
8
9
10
6
8
6
5
1
;
proc iml;
use have;
read all var _num_ into Pts[c=vname];
close;
indices = cvexhull(Pts); /* compute convex hull of the N points */
hullIdx = indices[loc(indices>0)];
P = Pts[hullIdx, ];
call sort(p,2);
create p from p[c=vname];
append from p;
close;
quit;
data p2;
set p;
sign=sign(dif(value));
run;
data p3;
set p2;
by sign notsorted;
if last.sign;
run;
data want;
set have p3(rename=(n=_n value=_v));
run;
proc sgplot data=want;
series x=n y=value;
scatter x=_n y=_v/markerattrs=(symbol=starfilled color=red);
run;
```

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

Thank you, Ksharp.

I am digesting your code 😆

HHC

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

I haven't heard the term "zigzag point" before, but it seems that you want to identify peaks and valleys in a noisy signal by using certain criteria about the height of the peaks and the width between peaks. In SAS Viya, you can use the PEAKLOC and PEAKINFO functions in SAS IML to identify peaks in a signal. These functions are not available in SAS 9.4.

SAS Event-Stream Processing also supports various methods for locating peaks.

Since this question appears related to time series, I will move it to a more appropriate community where experts like @rselukar might see it and provide additional assistance.

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

"In SAS Viya, you can use the PEAKLOC and PEAKINFO functions in SAS IML to identify peaks in a signal. These functions are not available in SAS 9.4. "

Disappointed . Need pay money for it .

Disappointed . Need pay money for it .

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

I might have to think about a way to include parameter to the code so I can provide more flexibility.

HHC

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

You can split this time series into many small series ,and use my code to get these points you want.

Or calling @Rick_SAS ,please let him wrote a IML code for you ?

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

The responses given so far are quite good. I am not aware of any thing in SAS/ETS or (SAS/ECONOMETRICS) that is specifically designed for peak-discovery. I think this problem can also be called identifying turning points of a time series. For noisy time series the interest could be in finding the turning points of the underlying smooth signal. I will describe a quick way of doing this by using PROC UCM in SAS/ETS. Of course, this is a solution to a related problem and not the original one.

Let's say the value_t series can be thought of as a sum of mu_t, a smooth curve, and noise_t: value_t = mu_t + noise_t. The following code shows you how to fit this model when mu_t is modeled by an integrated random walk, which produces cubic smoothing spline, and Gaussian white noise:

proc ucm data=have;

id n interval=obs;

model value;

irregular;

level variance=0 noest;

slope plot=smooth;

forecast lead=0 outfor=for plot=decomp;

run;

The output data set "for" contains the estimates of mu_t and its slope (the columns s_level and s_slope). The turning points of mu_t could be located as places where the sign of adjacent s_level values change (i.e., points where s_level stops going upward/downward). These points are located by the following data steps:

data change;

set for(keep=n value s_level s_slope);

s1 = lag(s_slope);

turn = 0;

if n >= 2 then do;

if sign(s1) ^= sign(s_slope) then turn=1;

end;

run;

*The turns data set contains the discovered turn points: 5 17 24;

data turns;

set change;

where turn=1;

run;

The following plot shows how well s_level approximates the original series:

The following curve plots the slope (s_slope):

The following code shows the discovered turning points:

proc sgplot data=change;

title Plot of smoothed_value with identified turning points;

series x=n y=s_level;

refline 5 17 24/ axis=x;

run;

Of course, the identified turning points are not the turning points of the original series but of the underlying smooth signal. The following plot shows how they appear for the original curve:

proc sgplot data=change;

title Plot of value with identified turning points for smoothed_value;

series x=n y=value;

refline 5 17 24/ axis=x;

run;

I know this is a bit lengthy response.

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

I tested rselukar 's code and got this :

```
data have;
set sashelp.stocks;
if stock='Intel';
keep date stock close;
run;
proc sort data=have;by date;run;
data have2;
set have(keep=close rename=(close=value));
n+1;
run;
proc ucm data=have2;
id n interval=obs;
model value;
irregular;
level variance=0 noest;
slope plot=smooth;
forecast lead=0 outfor=for plot=decomp;
run;
data change;
set for(keep=n value s_level s_slope);
s1 = lag(s_slope);
turn = 0;
if n >= 2 then do;
if sign(s1) ^= sign(s_slope) then turn=1;
end;
run;
data turns;
set change;
where turn=1;
run;
data all;
set have2 turns(keep=n value rename=(n=_n value=_v));
run;
proc sgplot data=all;
title Plot of smoothed_value with identified turning points;
series x=n y=value;
scatter x=_n y=_v/markerattrs=(symbol=starfilled color=red);
run;
```

**SAS Innovate 2025** is scheduled for May 6-9 in Orlando, FL. Sign up to be **first to learn** about the agenda and registration!

Multiple Linear Regression in SAS

Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.

Find more tutorials on the SAS Users YouTube channel.