The CESM Procedure
Example 8.1 Forecasting of Time Series Data
This example uses retail sales data to illustrate how you can use the CESM procedure to forecast time series data.
The statements in this example assume that your CAS engine libref is named mycas, but you can substitute any appropriately defined CAS engine libref.
The following DATA step creates a data table from data that were recorded monthly at numerous points of sale. The data table, mycas.sales, contains a variable Date (which represents time) and a variable for each sales item. Each value of the Date variable is recorded in ascending order, and the values of each of the other variables represent a single time series.
data mycas.sales;
format date date9.;
input date : date9. shoes socks laces dresses
coats shirts ties belts hats blouses;
datalines;
01JAN1994 3557 3718 6368.80 575 987 10.8200 15.0000 102.600 12410 15013
01FEB1994 5128 4174 8123.20 565 1000 12.1200 15.1000 99.900 13556 12413
01MAR1994 5222 4482 7807.20 406 1005 11.7800 15.3000 102.000 11063 12752
... more lines ...
01DEC1998 5399 4795 6075.30 614 1239 21.2000 1.9000 79.700 23004 22044
01JAN1999 6405 4981 6812.10 607 1196 20.7000 14.9000 99.900 20583 26093
;
The following CESM procedure statements forecast each of the monthly time series by using the simple exponential smoothing model:
proc cesm data=mycas.sales outfor=mycas.nextyear;
id date interval=month;
forecast _numeric_ / lead=12 method=simple;
run;
The preceding statements generate forecasts for every numeric variable in the input data table mycas.sales for the next 12 months and store these forecasts in the output data table mycas.nextYear. The summary of time series processing is output in Output 8.1.1.
Output 8.1.1: Summary of Time Series Processing
| Processing Summary | |
|---|---|
| CAS table | SALES |
| Number of analysis variables | 10 |
| Number of rows read | 122 |
| Number of groups read | 1 |
| Memory for group packages (KB) | 33 |
| Time to load groups (seconds) | 0.0119960308 |
| Minimum time ID | JAN1994 |
| Maximum time ID | JAN1999 |
| Minimum time periods | 61 |
| Maximum time periods | 61 |
| Number of nodes run | 4 |
| Number of nodes with data | 3 |
| Number of nodes with groups | 1 |
| Number of threads budgeted | 1 |
| Minimum thread group count | 0 |
| Maximum thread group count | 1 |
| Minimum threads active | 1 |
| Maximum threads active | 1 |
| Number of groups processed by submitted code | 1 |
| Number of groups failing | 0 |
| Elapsed time to process groups (seconds) | 0.0730199814 |
The following statements plot the forecasts for the sale of belts, blouses, and laces:
%macro plotActualPredict(ds,timeId,var,refValue,
xStart,xEnd,xBy,xLabel,yStart,yEnd,yBy,yLabel);
proc sgplot data=&ds.(where=(_name_="&var."));
series x=&timeId. y=actual / markers lineattrs=(color=red)
markerattrs=(symbol=circlefilled color=red);
series x=&timeId. y=predict / markers lineattrs=(color=blue)
markerattrs=(symbol=asterisk color=blue);
refline &refValue. / axis=x;
xaxis values=(&xStart. to &xEnd. by &xBy.) label=&xLabel;
yaxis values=(&yStart. to &yEnd. by &yBy.) label=&yLabel minor;
run;
%mend;
%plotActualPredict(mycas.nextyear, date, belts, '01JAN1999'd,
'01JAN1994'd, '01DEC2000'd, year, 'Date',
20, 140, 20, 'Sales');
%plotActualPredict(mycas.nextyear, date, blouses, '01JAN1999'd,
'01JAN1994'd, '01DEC2000'd, year, 'Date',
8000, 36000, 4000, 'Sales');
%plotActualPredict(mycas.nextyear, date, laces, '01JAN1999'd,
'01JAN1994'd, '01DEC2000'd, year, 'Date',
5000, 10000, 1000, 'Sales');
The plots are shown in Output 8.1.2, Output 8.1.3, and Output 8.1.4. The historical actual values and their predicted values are shown to the left of the reference line, and the forecasts for the next 12 monthly periods are shown to the right. For simple exponential smoothing models, the forecasts are constant. The plots seem to indicate that the fit of the predicted values to the actual values is not good.
Output 8.1.2: Retail Sales Forecast Plots (Belts)

Output 8.1.3: Retail Sales Forecast Plots (Blouses)

Output 8.1.4: Retail Sales Forecast Plots (Laces)

The following statements forecast each of the monthly time series by using the default METHOD=BEST option:
proc cesm data=mycas.sales outfor=mycas.nextyear outest=mycas.salesEst;
id date interval=month;
forecast _numeric_ / lead=12;
run;
The best method for each variable is selected according to the criterion (RMSE, the default value, in this case). The following statements plot the forecasts for the sale of belts, blouses, and laces:
%plotActualPredict(mycas.nextyear, date, belts, '01JAN1999'd,
'01JAN1994'd, '01DEC2000'd, year, 'Date',
20, 140, 20, 'Sales');
%plotActualPredict(mycas.nextyear, date, blouses, '01JAN1999'd,
'01JAN1994'd, '01DEC2000'd, year, 'Date',
8000, 36000, 4000, 'Sales');
%plotActualPredict(mycas.nextyear, date, laces, '01JAN1999'd,
'01JAN1994'd, '01DEC2000'd, year, 'Date',
5000, 10000, 1000, 'Sales');
The plots are shown in Output 8.1.5, Output 8.1.6, and Output 8.1.7. The fit of the predicted values to the actual values seems much better, so you might have more confidence in these forecasts.
Output 8.1.5: Retail Sales Forecast Plots (Belts)

Output 8.1.6: Retail Sales Forecast Plots (Blouses)

Output 8.1.7: Retail Sales Forecast Plots (Laces)

The following statements print the methods that are selected for each variable, as shown in Output 8.1.8:
data salesEst; set mycas.salesEst; run;
proc sort data=salesEst nodupkey; by _name_ _compmodel_; run;
proc print data=salesEst label noobs;
var _name_ _compmodel_;
label _name_='Variable' _compmodel_='Method';
run;
Output 8.1.8: Best Method for Each Variable
| Variable | Method |
|---|---|
| belts | SEASONAL |
| blouses | WINTERS |
| coats | ADDWINTERS |
| dresses | SEASONAL |
| hats | ADDWINTERS |
| laces | ADDWINTERS |
| shirts | ADDWINTERS |
| shoes | ADDWINTERS |
| socks | ADDWINTERS |
| ties | SEASONAL |