Utility Package
Example 18.1 Collecting Forecast Fit Statistics and Ad Hoc Numeric Variables into CAS Tables
This example demonstrates the capabilities of the UTLSTAT and OUTNVP collector objects from the UTL package. The UTLSTAT collector object is used to compute and collect forecast fit statistics for a specified pair of actual and predicted time series. In contrast, the OUTNVP collector object is used to store ad hoc numeric variables that are found in the user-defined program into CAS tables. The example starts by using a DATA step to load a sample time series data set called Sashelp.Air into a CAS table. The TSMODEL procedure is then invoked and the Time Series Model (TSM) object (available in the TSM package) is used to generate a model for the Air series in the Sashelp.Air data set. Next, both the actual Air series and its predicted counterpart (generated by the TSM object) are input into the UTLSTAT object to compute and collect numerous forecast fit statistics (see Table 18.7) into a CAS table. Because this example processes only a single time series (the Air series) and a single BY group, a single row of output is stored in the UTLSTAT table. The example then uses the OUTNVP collector object to store into a CAS table various forecast series that are retrieved from the TSM object. Each forecast series is first queried into a numeric array via the GetForecast method in the TSM object. Each array is then input directly, one by one, into the OUTNVP collector object. Finally, some results are retrieved from the resulting UTLSTAT and OUTNVP CAS tables, sorted, and printed for further inspection.
The following DATA step loads the Sashelp.Air data set onto the CAS server. This DATA step assumes that your CAS engine libref is named mycas, but you can substitute any appropriately defined CAS engine libref.
data mycas.air (replace=yes); set Sashelp.Air; run;
The following statements use the TSMODEL procedure to perform time series modeling on a single BY group. Because no ACCUMULATE= option is specified in the ID or VAR statements, its default value of TOTAL is used, which accumulates observations within a time period as a total sum of the nonmissing values.
proc tsmodel data=mycas.air
outarray = mycas.outarray (replace=yes)
outscalar = mycas.outscalar (replace=yes)
outobj=(
utlstatobj = mycas.utlstat (replace = YES)
outnvpmodelobj = mycas.outnvpmodel (replace = YES)
)
outlog = mycas.outlog (replace=yes)
lead=12;
id date interval=month start='01jan1949'd end='01dec1960'd;
outarray predict error stderr lcl ucl;
outscalar rc1 rc2 rc3 rc4 rc5 rc6 rc7 rc8;
var air;
require tsm utl;
submit;
/* Declare the "Time Series Model" (TSM) object and perform fit */
declare object esm(tsm);
rc1 = esm.Initialize();
if rc1 < 0 then do; stop; end;
rc1 = esm.SetY(air);
if rc1 < 0 then do; stop; end;
rc1 = esm.Run();
if rc1 < 0 then do; stop; end;
/* Retrieve forecast series computed internally by the TSM object */
rc2 = esm.GetForecast('predict',predict); /*Predicted series*/
if rc2 < 0 then do; stop; end;
rc2 = esm.GetForecast('error',error); /*Forecast error series*/
if rc2 < 0 then do; stop; end;
rc2 = esm.GetForecast('stderr',stderr); /*Prediction std. errors series*/
if rc2 < 0 then do; stop; end;
rc2 = esm.GetForecast('lower',lcl); /*Lower conf. limits series*/
if rc2 < 0 then do; stop; end;
rc2 = esm.GetForecast('upper',ucl); /*Upper conf. limits series*/
if rc2 < 0 then do; stop; end;
/* Collect forecast series computed by the TSM object into a CAS table */
declare object outnvpmodelobj(outnvp);
rc3 = outnvpmodelobj.Collect(air,_SERIES_);
if rc3 < 0 then do; stop; end;
rc3 = outnvpmodelobj.Collect(predict,_SERIES_);
if rc3 < 0 then do; stop; end;
rc3 = outnvpmodelobj.Collect(error,_SERIES_);
if rc3 < 0 then do; stop; end;
rc3 = outnvpmodelobj.Collect(stderr,_SERIES_);
if rc3 < 0 then do; stop; end;
rc3 = outnvpmodelobj.Collect(lcl,_SERIES_);
if rc3 < 0 then do; stop; end;
rc3 = outnvpmodelobj.Collect(ucl,_SERIES_);
if rc3 < 0 then do; stop; end;
/* Compute and collect a vast number of forecast fit statistics */
declare object utlstatobj(utlstat);
rc4 = utlstatobj.Collect(air, predict);
if rc4 < 0 then do; stop; end;
endsubmit;
run;
You can use the PRINT procedure to display a small subset of the 55 different forecast fit statistics that are collected by the UTLSTAT object. The PRINT procedure can access CAS tables directly; thus, there is no need to retrieve the UTLSTAT table back from CAS and into a local data set prior to display.
/* Print a few forecast fit statistics for the single BY group */
proc print data=mycas.utlstat;
var _NAME_ _MODEL_ NOBS RMSE MAPE MAE RSQUARE AIC;
run;
Output 18.1.1 shows that a single row of data was collected. This row corresponds to the forecast fit statistics that were collected for a single forecast (that is, one pair of actual and predicted series) within the single BY group that was processed by the TSMODEL procedure call.
Output 18.1.1: Sample of the Forecast Fit Statistics Computed and Collected by the UTLSTAT Object
You can use the PRINT procedure again to display a small subset of observations from the following six different series that were collected by the OUTNVP object into the mycas.outnvpmodel CAS table:
The actual series (that is, the
Airseries).The predicted series that was generated by the TSM object.
The forecast error series that was generated by the TSM object.
The prediction standard errors series that was generated by the TSM object.
The lower confidence limits series that was generated by the TSM object.
The upper confidence limits series that was generated by the TSM object.
You can print in sequence the values of the first three observations in each of these six series, for a total of 18 rows. To accomplish this, you must sort the mycas.outnvpmodel CAS table in a manner that sequentially aligns all rows that correspond to each unique observation index in all collected series (that is, all rows that correspond to the first observation in all six series, followed by all rows that correspond to the second observation in all six series, and so on). You can use the SORT procedure to simultaneously sort a CAS table and retrieve the results into a local data set as follows:
/* Sort OUTNVP table by "row index" and "BY group Collect() call count" */
/* (that is, _VIX_ and _CALL_ columns). Transfer the sorted table rows */
/* back from CAS and into a local data set. */
proc sort data=mycas.outnvpmodel out=outnvpmodel;
by _VIX_ _CALL_;
run;
/* Print the values of the first 18 rows, which correspond to the values */
/* of the first 3 observations in the six collected series. These 18 rows */
/* correspond to the condition "1 <= _VIX_ <= 3" in the CAS table called */
/* "MYCAS.OUTNVPMODEL". */
proc print data=outnvpmodel(obs=18);
run;
Output 18.1.2: Sample of the Six Ad Hoc Series Collected by the OUTNVP Object
| Obs | _VAR_ | _CALL_ | _UTAG_ | _VIX_ | _VALUE_ |
|---|---|---|---|---|---|
| 1 | AIR | 1 | 0 | 1 | 112 |
| 2 | predict | 2 | 0 | 1 | 111.44700541 |
| 3 | error | 3 | 0 | 1 | 0.5529945856 |
| 4 | stderr | 4 | 0 | 1 | 10.691036547 |
| 5 | lcl | 5 | 0 | 1 | 90.492958825 |
| 6 | ucl | 6 | 0 | 1 | 132.401052 |
| 7 | AIR | 1 | 0 | 2 | 118 |
| 8 | predict | 2 | 0 | 2 | 119.94581467 |
| 9 | error | 3 | 0 | 2 | -1.945814668 |
| 10 | stderr | 4 | 0 | 2 | 10.691036547 |
| 11 | lcl | 5 | 0 | 2 | 98.991768079 |
| 12 | ucl | 6 | 0 | 2 | 140.89986126 |
| 13 | AIR | 1 | 0 | 3 | 132 |
| 14 | predict | 2 | 0 | 3 | 135.17351431 |
| 15 | error | 3 | 0 | 3 | -3.173514311 |
| 16 | stderr | 4 | 0 | 3 | 10.691036547 |
| 17 | lcl | 5 | 0 | 3 | 114.21946772 |
| 18 | ucl | 6 | 0 | 3 | 156.1275609 |
The sequence that is displayed in Output 18.1.2 was obtained by using the SORT procedure to sort the data in the OUTNVP table in increasing order of the columns _VIX_ (series row index) and _CALL_ (that is, the OUTNVP object’s Collect method call count within BY group). For example, rows 1–6 contain the values of the first observation in each of the six collected series, which correspond to the rows in the mycas.outnvpmodel CAS table where column _VIX_ = 1: row 1 is the value of the first observation in the Air series (that is, column _VAR_ = AIR) and rows 2–6 are the values of the first observations in the Predict, Error, StdErr, LCL, and UCL forecast series that were retrieved from the TSM object via its GetForecast method. The same applies for the second observation in each of the six collected series as described by rows 7–12 (that is, rows where column _VIX_ = 2) and for the third observation in each of the six collected series as described by rows 13–18 (rows where column _VIX_ = 3).