Kernel Principal Component Analysis Action Set
Concentric Circles
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 to use the kPca action to project concentric data onto the first two kernel principal components. The following code shows how to generate this data set by using the IML procedure and how to plot it by using the SGPLOT procedure. The output is shown in Figure 1.
proc iml;
start Linspace(a, b, n);
if n<2 then return( b );
incr = (b-a) / (n-1);
return( do(a, b, incr) );
finish;
start makecircles(X, y, n_samples, noise, random_state, factor=0.8);
pi = constant("pi");
lins=Linspace(0, 2*pi, floor(n_samples/2)+1);
n_2=floor(n_samples/2);
lins=remove(lins,n_2+1);
outer_circ_x=cos(lins);
outer_circ_y=sin(lins);
inner_circ_x = outer_circ_x#factor;
inner_circ_y = outer_circ_y#factor;
X=(outer_circ_x||inner_circ_x)`||(outer_circ_y||inner_circ_y)`;
y=(j(1,n_2,0)||j(1,n_2,1))`;
Xy=X||y;
call randseed(random_state); /* shuffle observations */
obsIdx = sample(1:nrow(Xy), nrow(Xy), "NoReplace");
X=Xy[obsIdx,1:ncol(Xy)-1];
y=Xy[obsIdx,ncol(Xy)];
Xn=j(nrow(X),2);
if noise^=. then
call randgen(Xn, "Normal", 0, noise);
X=X+Xn;
finish;
n_samples=1000; /*sample size*/
noise=0.05;
random_state=0;
factor=0.3; /*radius ratio of outer and inner circle*/
run makecircles(X, y, n_samples, noise, random_state, factor);
circles=X||y;
create circles from circles[colname={"x" "y" "group"}];
append from circles;
close circles;
quit;
proc sgplot data=circles;
styleattrs datasymbols=(Circle X);
scatter x=x y=y / group=group markerattrs=(size=7px);
run;
Figure 1: Plot of the Two Concentric Circles

You can load the circles data into your CAS session by naming your CAS engine libref in the first statement of the following DATA step. These statements assumes your CAS engine libref is named mycas, but you can substitute any appropriately defined CAS engine libref.
data mycas.circles;
set circles;
run;
The following code uses the kPca action to project the circles data onto the first two kernel principal components and then use the SGPLOT procedure to plot the associated score values. The output is shown in Figure 2.
proc cas;
loadactionset "KernelPCA";
run;
action kPca result = r/table = {name='circles'},
output ={casout={name="scored", replace=TRUE}, copyvars={"y", "group"}, npc=2},
saveState={name="STATE", replace=TRUE},
input={{name="y"},{name="x"}},
method = "EXACT",
kerType="RBF",
kerParam=0.3;
run;
print r;
quit;
proc sgplot data=mycas.scored;
styleattrs datasymbols=(Circle X);
scatter x=_PCS_1 y=_PCS_2 / group=group markerattrs=(size=7px);
run;
Figure 2: Projection of the Two Concentric Circles onto the First Two Kernel Principal Components

In Figure 2, you can see that after you project the data onto the first two kernel principal components, the two circles are linearly separable. However, as you can see in Figure 3, the projection of the data onto the first two regular principal components is just a rotation of the original concentric pattern and thus is not linearly separable. (Note that when you use the linear kernel type, regular PCA is performed.) The following code runs the regular PCA on the Circles data table:
proc cas;
loadactionset "KernelPCA";
run;
action kPca result = r/table = {name='circles'},
output ={casout={name="scoredpca", replace=TRUE}, copyvars={"y", "group"}, npc=2},
saveState={name="STATE", replace=TRUE},input={{name="y"},{name="x"}},
method = "EXACT",
kerType="LINEAR";
run;
print r;
quit;
proc sgplot data=mycas.scoredpca;
styleattrs datasymbols=(Circle X);
scatter x=_PCS_1 y=_PCS_2 / group=group markerattrs=(size=7px);
run;
Figure 3: Projection of the Two Concentric Circles onto the First Two Regular Principal Components

Concentric Circles Data
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 circles data to the comma-separated-value (CSV) file circles.csv and then use the following code to load the CSV file into CAS:
s:loadtable{casLib="casuser", path="circles.csv"}
For more information about coding in Lua, see Getting Started with SAS Viya for Lua and SAS Viya: System Programming Guide.
-- call kernelPca.kPca action with RBF kernel --
res = s:kernelPca_kPca{table={name="circles"},
method="EXACT",
kerParam= 0.3,
kerType="RBF",
inputs={{name="x1"},{name="x2"}},
output={casout={name="scored", replace=true},
copyVars={"x1","x2","group"}, npc=2}
}
print (res)
r=s:fetch{table={name="scored"},to=all}
print(r)
-- call kernelPca.kPca action with LINEAR kernel (equivalent to PCA) --
res = s:kernelPca_kPca{table={name="circles"},
method="EXACT",
kerType="LINEAR",
inputs={{name="x1"},{name="x2"}},
output={casout={name="scored_pca", replace=true},
copyVars={"x1","x2","group"}, npc=2}
}
print (res)
r=s:fetch{table={name="scored_pca"},to=all}
print(r)
Concentric Circles Data
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 circles data to the comma-separated-value (CSV) file circles.csv and then use the following code to load the CSV file into CAS:
s.upload_file('circles.csv')
For more information about coding in Python, see Getting Started with SAS Viya for Python and SAS Viya: System Programming Guide.
import matplotlib.pyplot as plt
# apply KPCA to circles data with RBF kernel
res = s.kernelPca.kPca(inputs= [{"name":"x1"},{"name":"x2"}]
,output={'casout':{'name':'scored', 'replace':True},
'copyVars':["x1","x2","group"], 'npc':2}
,table=table('circles')
,method="EXACT"
,kerType="RBF"
,kerParam=0.3)
print(res)
scored = s.fetch(table = {"name":"scored"}, to=5000, maxrows=5000)["Fetch"]
scored=scored.values
# apply KPCA to circles with LINEAR kernel (equivalent to PCA)
res = s.kernelPca.kPca(inputs= [{"name":"x1"},{"name":"x2"}]
,output={'casout':{'name':'scored_pca', 'replace':True},
'copyVars':["x1","x2","group"], 'npc':2}
,table=table('circles')
,method="EXACT"
,kerType="LINEAR")
scored_pca = s.fetch(table = {"name":"scored_pca"}, to=5000, maxrows=5000)["Fetch"]
scored_pca=scored_pca.values
#plotting code
plt.figure()
plt.subplot(2, 2, 1, aspect='equal')
plt.title("Original space")
reds = scored[:,2] == 0
blues = scored[:,2] == 1
plt.scatter(scored[reds, 0], scored[reds, 1], c="blue",
s=20, edgecolor='k')
plt.scatter(scored[blues, 0], scored[blues, 1], c="red",
s=20, edgecolor='k')
plt.xlabel("$x_1$")
plt.ylabel("$x_2$")
plt.subplot(2, 2, 2, aspect='equal')
plt.scatter(scored[reds, 3], scored[reds, 4], c="blue",
s=20, edgecolor='k')
plt.scatter(scored[blues, 3], scored[blues, 4], c="red",
s=20, edgecolor='k')
plt.title("Projection by KPCA")
plt.xlabel("1st principal component")
plt.ylabel("2nd component")
plt.subplot(2, 2, 3, aspect='equal')
plt.scatter(scored_pca[reds, 3], scored_pca[reds, 4], c="blue",
s=20, edgecolor='k')
plt.scatter(scored_pca[blues, 3], scored_pca[blues, 4], c="red",
s=20, edgecolor='k')
plt.title("Projection by PCA")
plt.xlabel("1st principal component")
plt.ylabel("2nd component")
plt.tight_layout()
plt.show()
Concentric Circles Data
This section contains R 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 circles data to the comma-separated-value (CSV) file circles.csv and then use the following code to load the CSV file into CAS:
m <- cas.read.csv(s, "circles.csv", casOut=list(name="circles"))
For more information about coding in R, see Getting Started with SAS Viya for R and SAS Viya: System Programming Guide.
The SAS Scripting Wrapper for Analytics Transfer (SWAT) is an R package that enables you to interface with SAS Cloud Analytics Services (CAS). You can use the SWAT package to write R code to connect to a CAS server and analyze data. For more information about SWAT package; see Getting Started with SAS Viya for R.
The following code assumes that the training data set and the scoring data set are uploaded to CAS tables using appropriate functions available in the SWAT package.
library('swat')
loadActionSet(s, "kernelPca")
results <- cas.kernelPca.kPca(s,kerParam = 0.3,
method="EXACT",
kerType="RBF",
inputs = list(list(name = "x1"),
list(name = "x2")),
output=list(casOut=list(name="scored",replace=TRUE),
copyVars=list("x1","x2","group"),npc=2),
table=list(name="circles"))
scored <- cas.table.fetch(s, table = list(name = "scored"), maxRows = 5000, to = 5000)
scored_df = scored$Fetch
results <- cas.kernelPca.kPca(s,
method="EXACT",
kerType="LINEAR",
inputs = list(list(name = "x1"),
list(name = "x2")),
output=list(casOut=list(name="scored_pca",replace=TRUE),
copyVars=list("x1","x2","group"),npc=2),
table=list(name="circles"))
scored_pca <- cas.table.fetch(s, table = list(name = "scored_pca"), maxRows = 5000,
to = 5000)
scored_pca_df = scored_pca$Fetch