The CSSM Procedure

Example 13.20 Monitoring Streaming Data Using Scoring

This example shows how you can use the scoring functionality to monitor a continuous stream of observations. The goal is to detect structural changes in the observation process as soon as possible. For illustration purposes, the example uses the quarterly bivariate series (f_KSI, r_KSI), which is discussed in Example 13.1. The variable f_KSI represents the quarterly average of the log of the monthly totals of front-seat passengers who are killed or seriously injured during car accidents, and r_KSI represents a similar number for rear-seat passengers. Recall that the seatbelt data set contains 16 years of series values, starting from the first quarter of 1969. This example uses the first 13 years—52 quarters—of data (through the last quarter of 1981) to fit a suitable model for the series and to create a score store that saves the context for later use. It is assumed that the fitted model continues to hold in the subsequent years. Monitoring of the process starts with the first quarter of 1982. The remaining 12 rows of the seatbelt data set are processed one by one and mimic a quarterly streaming data sequence. In real-world applications, the data source can be more general, and the observations could arrive at a much higher frequency, such as every minute.

Assume that the model for bold y = (f_KSI, r_KSI) is

bold y Subscript t Baseline equals mu mu Subscript t Baseline plus zeta zeta Subscript t Baseline plus xi xi Subscript t

where

  • mu mu Subscript t denotes a bivariate random walk. To capture the fact that f_KSI and r_KSI move together (that is, they are co-integrated), the covariance of the disturbance term of this random walk is assumed to be of less than full rank.

  • zeta zeta Subscript t denotes a bivariate, time-invariant, trigonometric seasonal term.

  • xi xi Subscript t denotes a bivariate white noise term.

This model is the same as the one used in Example 13.1, except that in this case no correction is made for the seat-belt law of 1983. In fact, the goal of this exercise is to determine, without the knowledge of this law, whether the level shift in the front-seat passenger series that is caused by this law can be detected during this monitoring.

The following DATA step loads the first 13 years of data into the CAS table mycas.train:

data mycas.train;
    set seatBelt(obs=52);
run;

The following statements specify and fit the model, and save the scoring context in the CAS table mycas.inscore:

proc cssm data=mycas.train opt(tech=activeset);
   id date interval=quarter;
   state error(2) type=WN cov(g);
   component wn1 = error[1];
   component wn2 = error[2];
   state level(2) type=RW cov(rank=1) checkbreak;
   component rw1 = level[1];
   component rw2 = level[2];
   state season(2) type=season(length=4);
   component s1 = season[1];
   component s2 = season[2];
   model f_KSI = rw1 s1  wn1;
   model r_KSI = rw2 s2 wn2;
   output break(alpha=0.01) ao(alpha=0.01);
   score out(10)=mycas.inscore;
run;

Note that, because the OUT(k)= form of the OUT option is used in the SCORE statement (score out(10)=mycas.inscore;), mycas.inscore retains the context information from the last 10 quarters (from 1979/3 to 1981/4). The score store also retains the structural break detection settings that are specified in the STATE statement for level, and it retains the significance levels for the additive outlier detection and structural break detection that are specified in the OUTPUT statement.

After the model fitting and the initial score-store creation, the monitoring of streaming data is done using the following steps:

  • Starting with 1982/1 (which happens to be the 53rd row of seatbelt), successive quarters are loaded into mycas.nextObs one at a time; that is, mycas.nextObs always has just one row.

  • Each quarter is scored by using mycas.inscore and, additionally, an output score store (mycas.outscore) is created that incorporates the information in the current observation (score in=mycas.inscore out=mycas.outscore;).

  • The two score stores, mycas.inscore and mycas.outscore, are swapped so that mycas.outscore becomes the input score store for the next observation.

The following macro, %STREAM, accomplishes these three steps:

%macro STREAM;
  %do i=53 %to 64;
    /* read the next row */
    data mycas.nextObs;
       set seatBelt(firstobs=&i obs=&i);
    run;
    /* score the row that is read */
    proc cssm data=mycas.nextObs;
       ods output AOSummary=ao&i;
       ods output StateElementBreakSummary=ls&i;
       %if &i = 53 %then %do;
          ods output IdInformation=idInfo;
          ods output ResponseInfo=respInfo;
       %end;
       score in=mycas.inscore out=mycas.outscore;
    run;
    /* swap inscore and outscore */
    proc cas;
       table.altertable/name="outscore", rename="tmp";
       table.altertable/name="inscore", rename="outscore";
       table.altertable/name="tmp", rename="inscore";
    quit;
  %end;
%mend;

%STREAM;

For each new quarter, the %STREAM macro saves the results, if any, of the additive outlier detection and the structural break detection in SAS data sets (ods output AOSummary=ao&i; and ods output StateElementBreakSummary=ls&i;). For the first quarter, the ID information table and the response information table are also saved. The ID information table for the first quarter (1982/1) is shown in Output 13.20.1. Note that even though the input table (mycas.nextObs) has just one observation (which corresponds to 1982/1), it shows that PROC CSSM processed 11 observations (from 1979/3 to 1982/1). This is because, internally, PROC CSSM works with a data set that is created by combining the information of the previous ten quarters (1979/3 to 1981/4) that is present in the input score-store and the one quarter (1982/1) that is present in the current input data table (mycas.nextObs).

Output 13.20.1: ID Variable Information at the Start of Scoring

ID Variable Information

NameStartEndNumberDistinctMaximumDeltaType
date1979/31982/1111.0000Regular


For the same reason, Output 13.20.2 also shows the response variable information for 11 quarters.

Output 13.20.2: Response Variable Information at the Start of Scoring

Response Variable Information

NameNObsNMissInducedNMissMinimumMaximumMeanStdDev
f_KSI11006.4646.7996.6630.1147
r_KSI11005.6356.1195.9140.1610


The outlier detection and the structural break detection, which are performed after the arrival of each new quarterly observation, also happen for the set of 11 observations that is formed by the current observation and the observations in the 10 previous quarters. It happens that no additive outliers or structural breaks are detected in the four quarters of 1982. However, starting with the first quarter of 1983 (when the seat-belt law is introduced), additive outliers and structural breaks are detected in each quarter. The aggregate summary of this detection activity (obtained by combining the following pairs of data sets: ao57 with ao64 and ls57 with ls64) is shown in two tables: Output 13.20.3 shows the results of break detection for the bivariate state, level, and Output 13.20.4 shows the results of the additive outlier detection. In both tables, an extra column, obs_date, is added that indicates the quarter associated with the observation that was scored. In addition, two more columns, zValue (= Estimate/StdErr) and ProbZ (the corresponding p-value), are added to the additive outlier table for ease of comparison with the break detection table. An examination of the two tables shows the following:

  • When the observation associated with the first quarter of 1983 is processed, an additive outlier is flagged for f_ksi and a structural break is flagged at the first element of the bivariate state, level, both at time 1983/1. Recall that the first element of level corresponds to f_ksi. The associated zValue, –7.66, is the same in both cases. This makes sense, because at this point it is difficult to determine whether the unusually low f_ksi value is attributable to a shift in the level or is simply a one-time change.

  • When the observation that is associated with the second quarter of 1983 is processed, 1983/1 is again flagged as an additive outlier for f_ksi and as a structural break for the first element of level. The only difference is that the evidence for a structural break has become stronger than before (more extreme Z-value: –9.23), whereas the evidence for an additive outlier has weakened (less extreme Z-value: –5.67).

  • When the observation associated with the third quarter of 1983 is processed, 1983/1 continues to be flagged as a structural break for the first element of level, but it is no longer the most extreme additive outlier for f_ksi. Instead, 1983/1 is flagged as an additive outlier for r_ksi, because it has a larger value than expected! This is understandable because, as the model shows, f_KSI and r_KSI move together, so the 1983/1 value of r_ksi should have been lower than the observed value.

  • As more observations are processed, the evidence for 1983/1 being the location of the level shift in f_KSI keeps getting stronger.

In real-world applications, when sufficient evidence for a break is gathered, the monitoring is paused and some appropriate action is taken.

Output 13.20.3: Level Shift Detection during the Monitoring of 1982/1 to 1984/4

Detection of Break in the Bivariate State: Level

obs_dateTimeStateBreakElementIndexzValueProbZ
1983/11983/1level1-7.66<.0001
1983/21983/1level1-9.23<.0001
1983/31983/1level1-10.50<.0001
1983/41983/1level1-11.60<.0001
1984/11983/1level1-13.17<.0001
1984/21983/1level1-14.43<.0001
1984/31983/1level1-15.10<.0001
1984/41983/1level1-16.12<.0001


Output 13.20.4: Additive Outlier Detection during the Monitoring of 1982/1 to 1984/4

Detection of Additive Outliers

obs_dateTimeNameEstimateStdErrzValueProbZ
1983/11983/1f_KSI-0.35050.0458-7.66<.0001
1983/21983/1f_KSI-0.23450.0413-5.67<.0001
1983/31983/1r_KSI0.26690.04885.465<.0001
1983/41983/1r_KSI0.26580.04885.442<.0001
1984/11984/1r_KSI0.32160.04906.566<.0001
1984/21984/1r_KSI0.32260.04886.615<.0001
1984/31984/1r_KSI0.32320.04876.632<.0001
1984/41984/1r_KSI0.32390.04876.648<.0001


Last updated: January 27, 2023