Robust PCA Action Set

Detecting Anomalies

This section contains PROC CAS code.

Note: Input data must be accessible in your CAS session, either as a CAS table or as a transient-scope table. A CAS table has a two-level name: the first level is your CAS engine libref, and the second level is the table name. You refer to this table in the CAS procedure by specifying only the second level. For more information about two-level names, see Chapter 2, Shared Concepts (SAS Visual Data Mining and Machine Learning: Procedures). A transient-scope table is called directly from the action and exists in memory for the duration of the action. For more information about accessing data, see SAS Viya: System Programming Guide. For more information about PROC CAS and programming in CASL, see SAS Cloud Analytic Services: CASL Programmer’s Guide and SAS Cloud Analytic Services: CASL Reference.

This example shows how you can use the robustPca action to detect anomalies. The input data table mycas.rpcaData2 has 50 observations and three variables: Index, X, and Y. Index is simply an observation number, X is a randomly generated number between 0 and 1, and Y is X plus a random term between -1 and 1. This data table also has three outliers for variable Y in observations 7, 20, and 33.

The following DATA step creates the rpcaData2 data set:

    data rpcaData2;
    input index X Y;
    datalines;
    1    0.522    0.510
    2    0.642    0.583
    3    0.628    0.543
    4    0.826    0.875
    5    0.101    0.031
    6    0.310    0.311
    7    0.447    4.421
    8    0.419    0.481
    9    0.861    0.874
    10    0.418    0.334
    11    0.929    1.020
    12    0.946    0.946
    13    0.548    0.567
    14    0.626    0.643
    15    0.616    0.581
    16    0.684    0.622
    17    0.438    0.450
    18    0.264    0.174
    19    0.705    0.607
    20    0.932    3.024
    21    0.866    0.836
    22    0.145    0.138
    23    0.225    0.133
    24    0.577    0.515
    25    0.815    0.832
    26    0.678    0.706
    27    0.844    0.892
    28    0.996    1.033
    29    0.695    0.676
    30    0.988    0.930
    31    0.684    0.614
    32    0.582    0.660
    33    0.048    2.004
    34    0.230    0.276
    35    0.928    0.885
    36    0.509    0.539
    37    0.187    0.224
    38    0.339    0.405
    39    0.726    0.782
    40    0.459    0.463
    41    0.938    1.038
    42    0.435    0.451
    43    0.520    0.535
    44    0.051    0.146
    45    0.951    1.017
    46    0.173    0.199
    47    0.164    0.119
    48    0.773    0.834
    49    0.428    0.336
    50    0.864    0.918
    ;
    run;

You can load rpcaData into your CAS session by naming your CAS engine libref in the first statement of the following DATA step:

data mycas.rpcaData2;
    set rpcaData2;
run;

This statement assumes your CAS engine libref is named mycas, but you can substitute any appropriately defined CAS engine libref.

The following statements run the robustPca action.

 proc cas;
     ods trace on;
     loadactionset "robustPca";
     action robustPca /
         table={name="rpcaData2"}
         id={"index"}
         lambdaWeight=3.5
         outmat={sparseMat={name="sparsemat2" replace=True}}
     ;
 run;

If you look at the output data table mycas.sparsemat2 in the CAS engine library, you can see that the only nonzero values in the sparse matrix are related to the outlier values that were introduced for variable Y (in observations 7, 20, and 33).

Alternatively, you can set the anomalyDetection parameter to True in the robustPca action and then use the astore action to detect the outliers, as in the following statements:

 proc cas;
     ods trace on;
     loadactionset "robustPca";
     action robustPca /
         table={name="rpcaData2"}
         id={"index"}
         scale=True
         center=True
         saveState={name="store" replace=True}
         anomalyDetection=True
     ;
 run;

 proc cas;
     loadactionset "astore";
     action score /
     table={name="rpcaData2"}
     options={{name="RPCA_PROJECTION_TYPE",value=2}}
     rstore={name="store"}
     casout={name="scored",replace=True}
     ;
 run;

If you look at the mycas.scored data table in the CAS engine library, you can see that the same outliers (observations 7, 20, and 33) are detected. The two methods that are described in this section are not exactly the same, but with proper settings they both detect outliers.

Detecting Anomalies

This section contains Lua code for the analysis in the CASL version of this example, which contains details about the results.

Note: In order to run this code, the data that are described in the CASL version need to be accessible to the CAS server. One way to do this is to convert the rpcaData2 data to the comma-separated-value (CSV) file rpcaData2.csv and then use the following code to load the CSV file into CAS:

s:loadtable{casLib="casuser", path="rpcaData2.csv"}

For more information about coding in Lua, see Getting Started with SAS Viya for Lua and SAS Viya: System Programming Guide.

s:loadactionset{actionset="robustPca"}

s:robustPca{
   table={name="rpcaData2"},
   id={"index"},
   lambdaWeight=3.5,
   outmat={sparseMat={name="sparsemat2", replace=True}}
}

s:robustPca{
   table={name="rpcaData2"},
   id={"index"},
   scale=True,
   center=True,
   saveState={name="store", replace=True},
   anomalyDetection=True
}

s:loadactionset{actionset="astore"}
s:score{
   table={name="rpcaData2"},
   options={{name="RPCA_PROJECTION_TYPE",value=2}},
   rstore={name="store"},
   out={name="scored",replace=True}
}

s:fetch{table={name="scored"}, to=50}

Detecting Anomalies

This section contains Python code for the analysis in the CASL version of this example, which contains details about the results.

Note: In order to run this code, the data that are described in the CASL version need to be accessible to the CAS server. One way to do this is to convert the rpcaData2 data to the comma-separated-value (CSV) file rpcaData2.csv and then use the following code to load the CSV file into CAS:

s.upload_file('rpcaData2.csv')

For more information about coding in Python, see Getting Started with SAS Viya for Python and SAS Viya: System Programming Guide.

s.loadactionset(actionset="robustPca")
s.robustPca(
   table={"name" : "rpcaData2"},
   id={"index"},
   lambdaWeight=3.5,
   outmat={"sparseMat":{"name":"sparsemat2", "replace":True}}
)

s.fetch(table={"name":"sparsemat2"}, to=50)

 s.robustPca(
   table={"name" : "rpcaData2"},
   id={"index"},
   scale=True,
   center=True,
   saveState={"name":"store", "replace":True},
   anomalyDetection=True
)

s.loadactionset(actionset="astore")
s.score(
   table={"name" : "rpcaData2"},
   options=[{"name":"RPCA_PROJECTION_TYPE","value":2}],
   rstore={"name":"store"},
   out={"name":"scored","replace":True}
)

s.fetch(table={"name":"scored"}, to=50)

Detecting Anomalies

This section contains R code for the analysis in the CASL version of these examples, which contains details about the results.

Note: In order to run this code, the data that are described in the CASL version need to be loaded into CAS. One way to do this is to convert the rpcaData2 data set to the comma-separated-value (CSV) file rpcaData2.csv then use the following code to load the CSV file into CAS:

data <- cas.read.csv(s,
                    "rpcaData2.csv",
                    header= TRUE,
                    casOut=list(name="rpcaData2",replace=TRUE))

loadActionSet(s,'robustPca')
rs <- cas.robustPca.robustpca(s,
                    table =list(name="rpcaData2"),
                    id=list("index"),
                    lambdaweight=3.5,
                    outmat=list(sparseMat =list(name="sparsemat2",replace=TRUE)))

cas.table.fetch(s, table = list(name = 'sparsemat2'), to = 50)

rs <- cas.robustPca.robustpca(s,
                    table =list(name="rpcaData2"),
                    id=list("index"),
                    scale=TRUE,
                    center=TRUE,
                    saveState=list(name="store",replace=TRUE),
                    anomalyDetection=TRUE)

loadActionSet(s,'astore')
rs <- cas.astore.score(s,
                   table =list(name="rpcaData2"),
                   options=list(list(name="RPCA_PROJECTION_TYPE",value=2)),
                   rstore=list(name="store"),
                   out=list(name="scored",replace=TRUE))

cas.table.fetch(s, table = list(name = 'scored'), to = 50)

Last updated: September 15, 2022