K‑means clustering is one of the most widely used techniques for discovering structure in unlabeled data. Whether the goal is segmenting customers, grouping regions, or exploring patterns in large datasets, k-means provides a fast and intuitive way to turn raw data into meaningful clusters.
SAS Viya includes PROC KCLUS, a high‑performance procedure for k‑means clustering that runs in CAS and scales to large, wide datasets. In this two‑part series, I’ll walk through practical examples of using PROC KCLUS. Part 1 focuses on a small, interpretable dataset that makes it easy to see how the procedure works and how to evaluate the results. Part 2 will apply the same workflow to a more complex business dataset where clustering supports customer segmentation and downstream modeling.
This analysis is performed in SAS Studio (called SAS Data and AI Studio beginning with Viya 2026.06). All code shown here runs in SAS Studio and does not use other Viya interfaces such as Model Studio or Visual Analytics.
K-means clustering
K‑means clustering is an iterative, distance‑based method used to partition the rows of a data set into k mutually exclusive groups. Each cluster is represented by a centroid, which is the mean vector of the variables used in the analysis. The algorithm relies on Euclidean distances, so it is designed for continuous variables. Variants such as k‑modes and k‑prototypes extend the idea to categorical or mixed data by using different distance calculations, but the core k‑means algorithm assumes continuous inputs.
Choosing good predictors is essential. Variables should be continuous or have several levels if categorical, be relatively independent, and—most importantly—be relevant to the business or research goal. Clustering is only useful when the variables create meaningful differences between observations. In practice, analysts often select a small number of predictors to keep the resulting clusters interpretable.
Number of clusters
In many applications, the number of clusters is determined by business needs. For example, a marketing team may want three customer segments to align with existing campaign structures, or an operations group may require a fixed number of customer service tiers, which determines how many clusters the analysis should produce. In these cases, k is chosen to match organizational requirements rather than derived from the data.
When there is no a priori value for k, PROC KCLUS can estimate a reasonable number of clusters using the Aligned Box Criterion (ABC). ABC evaluates cluster separation across a range of candidate values for k and identifies the value that maximizes separation quality. If a clear global maximum cannot be found, PROC KCLUS selects k based on the largest gap value, which reflects the point where adding additional clusters no longer improves separation meaningfully. ABC provides a data‑driven way to select the number of clusters when k is not known in advance.
Standardizing variables
Variables that are used to form clusters should be put on a similar scale. If they are not on a similar scale, the more variable inputs will dominate the clustering process. Options within PROC KCLUS include standard deviation (z-score) standardization, range standardization (transforming variables so they have a minimum of 0 and maximum of 1), and no standardization. Standard deviation (z-score) standardization is most useful when variables are roughly normally distributed. Range standardization is especially useful when variables have very different scales or are highly skewed. No standardization is only recommended if the variables are already on a similar scale.
Census2000 data
In this next section, I’ll use the Census2000 data to illustrate the workflow. This dataset contains postal‑code–level summaries from the 2000 United States Census and includes variables such as median household income, average household size, and regional density percentile. It includes the following variables:
| Variable | Label |
| ID | Region ID |
| LocX | Region Logitude |
| LocY | Region Latitiude |
| MeanHHSz | Average Household Size |
| MedHHInc | Median Household Income |
| RegDens | Region Density Percentile |
| RegPop | Region Population |
The goal of this analysis is to group U.S. regions into distinct subsets based on demographic factors using the k‑means algorithm. Clustering regions on demographic variables can be useful for understanding broad patterns in household composition, income, and urbanicity. These patterns often appear in applications such as market analysis, resource allocation, and exploratory segmentation.
To decide which variables to use, we’ll examine summary statistics and correlations for the four demographic variables: MeanHHSz, MedHHInc, RegDens, and RegPop. The spatial variables (LocX and LocY) are excluded so that clusters reflect demographic patterns rather than geographic location.
The data are already loaded into CAS. I’ll use PROC CARDINALITY and PROC CORRELATION to explore the Census2000 table. These procedures help identify missing values, choose an appropriate scaling method, and select relatively uncorrelated inputs for clustering.
proc cardinality data=mycas.census2000 outcard=uml2.census_card;
var MeanHHSz MedHHInc RegDens RegPop;
run;
proc print data=mycas.census_card label;
var _varname_ _type_ _nobs_ _nmiss_ _mean_ _stddev_ _skewness_ _kurtosis_;
run;
proc correlation data=mycas.census2000;
var MeanHHSz MedHHInc RegDens RegPop;
run;
Results
Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.
The Census2000 table contains 33,178 observations. PROC CARDINALITY shows that RegDens has over 1,000 missing values, which would require imputation if this variable is included in the clustering. The summary statistics indicate that MedHHInc and RegPop are right‑skewed (positive skewness) with heavy tails (positive kurtosis), while MeanHHSz is left‑skewed (negative skewness) and also heavy‑tailed. RegDens has near‑zero skewness and low kurtosis, which is consistent with its construction as a percentile variable and therefore approximately uniform.
For k‑means clustering to perform well, variables must be placed on a similar scale so that no single variable dominates the distance calculations. The distributional differences shown here suggest using range standardization rather than traditional z‑score standardization, which can perform poorly when variables have strong skewness or extreme values.
The PROC CORRELATION output shows that several variables have minimum values of zero; a full analysis might investigate whether these values are reasonable, but we leave them as is for this example. The correlation matrix indicates that RegDens and RegPop have the strongest association (r = 0.61). To avoid redundancy and focus on relatively independent inputs, we select MeanHHSz, MedHHInc, and RegDens as the clustering variables for the k‑means analysis.
Clustering the Census2000 Data with PROC KCLUS
The code below runs the k‑means clustering algorithm using PROC KCLUS. The IMPUTE=mean option replaces missing values with the arithmetic mean. STANDARDIZE=range scales each variable to the interval [0, 1], which is appropriate for variables with different scales and skewness. NOC=ABC (ALIGN=none) uses the aligned box criterion to determine the number of clusters. INIT=forgy selects initial cluster centers by randomly choosing observations. The OUTSTAT= option saves cluster centroid statistics to mycas.census_clus_outstat. The SCORE statement assigns each observation to a cluster and writes the results to mycas.census_clusters. COPYVARS=(_all_) adds all original variables to the scored output table.
In addition, PROC KCLUS automatically adds the _CLUSTER_ID_ variable, the _DISTANCE_ variable, and—when standardization is requested—the _STANDARDIZED_DISTANCE_ variable to the data set specified in the SCORE statement. _DISTANCE_ gives the Euclidean distance from each observation to its assigned cluster centroid, and _STANDARDIZED_DISTANCE_ provides the same distance computed using the standardized variable scale.
proc kclus data=mycas.census2000 impute=mean standardize=range noc=ABC
(Align=none) init=forgy outstat=uml2.census_clus_outstat;
input MeanHHSz MedHHInc RegDens/level=interval;
score out=uml2.census_clusters copyvars=(_all_);
run;
proc print data=mycas.census_clus_outstat;
run;
Results
The Model Information table confirms that k‑means clustering was run with three clusters, as selected by the aligned box criterion (ABC). All 33,178 observations were used. Range standardization was applied, missing values were imputed using the mean, and initial cluster centers were chosen using the Forgy method. The algorithm used Euclidean distance and converged within the maximum of 10 iterations.
The ABC Parameters table shows that the aligned box criterion evaluated cluster counts from 2 through 6. The ABC Statistics table reports the gap statistic for each candidate number of clusters. The largest gap occurs at three clusters, indicating that three clusters provide the best separation relative to a reference distribution. This result is consistent with the GlobalPeak criterion shown later.
The Estimated Number of Clusters table confirms that the GlobalPeak criterion selected three clusters. The Descriptive Statistics table restates the means and standard deviations of the three input variables prior to clustering.
The Within‑Cluster Statistics table shows the mean and standard deviation of each variable within each cluster, after range standardization. These values describe the cluster centroids and the spread of observations around each centroid. The Standardization table lists the location and scale values used to transform each variable to the [0, 1] range.
The Cluster Summary table reports the number of observations in each cluster and the distribution of distances from each observation to its cluster centroid. These values indicate how tightly grouped each cluster is. The Iteration History table shows the reduction in within‑cluster SSE across iterations, confirming that the algorithm converged within the allowed number of iterations.
The final table lists the cluster centroids in both original units and standardized units. These values summarize the demographic characteristics of each cluster. Cluster 2 has the highest median household income and the highest density percentile, representing more urban and higher‑income regions. Cluster 3 has lower income and much lower density, representing more rural areas. Cluster 1 lies between the two, with moderate density and moderate income. These centroid values define the three demographic clusters produced by the k‑means algorithm.
Note: In the centroid table, the standardized median income values (S_MedHHInc) appear as zeros because the column is displayed with a coarse numeric format. The actual standardized values are small decimals (approximately 0.17, 0.24, and 0.16), which round to zero under this format. The underlying values match the standardized means shown in the Within Cluster Statistics table.
Preparing a Sample for Visualization
Next, we create a smaller subset of the data for plotting. Scatterplots with over 30,000 observations are difficult to interpret, so we take a stratified random sample of approximately 15% of the data (about 5,000 rows). The BY statement in PROC PARTITION performs the stratified sampling by drawing a separate random sample within each cluster, ensuring that the proportion of observations in each cluster is preserved.
proc partition data=mycas.census_clusters samppct=15 seed=12345;
by _CLUSTER_ID_;
output out=uml2.census_clusters_sample copyvars=(_all_);
run;
Results
The PARTITION output lists the number of observations in each cluster and the number of sampled observations drawn from each cluster. Because sampling was stratified by _CLUSTER_ID_, each cluster contributes a proportional number of rows to the sample. The resulting sample contains 4,977 rows and 10 variables.
Visualizing the Clusters with Scatterplots
The PROC SGPLOT code below is used to visualize the clusters. Each scatterplot shows a pair of the three input variables, with points colored by cluster assignment. Ellipses summarize the spread of each cluster and help highlight the separation between groups in the sampled data. The ellipses are geometric data ellipses based on the sample covariance matrix; they represent roughly two standard deviations of spread and are not confidence or prediction intervals.
proc sgplot data=uml2.census_clusters_sample;
scatter x=RegDens y=MeanHHSz/group=_CLUSTER_ID_ transparency=0.7 markerattrs=(symbol=CircleFilled size=4);
ellipse x=RegDens y=MeanHHSz/group=_CLUSTER_ID_;
run;
proc sgplot data=uml2.census_clusters_sample;
scatter x=RegDens y=MedHHInc/group=_CLUSTER_ID_ transparency=0.7 markerattrs=(symbol=CircleFilled size=4);
ellipse x=RegDens y=MedHHInc/group=_CLUSTER_ID_;
run;
proc sgplot data=uml2.census_clusters_sample;
scatter x=MedHHInc y=MeanHHSz/group=_CLUSTER_ID_ transparency=0.7 markerattrs=(symbol=CircleFilled size=4);
ellipse x=MedHHInc y=MeanHHSz/group=_CLUSTER_ID_;
run;
Results
The scatterplots provide a visual confirmation of the cluster structure identified by PROC KCLUS. In the Household size vs. regional density plot, Cluster 2 appears in high‑density areas, Cluster 3 in low‑density areas, and Cluster 1 in the middle. In the Household income vs. regional density plot, the same pattern emerges: Cluster 2 occupies higher‑income, more urban regions; Cluster 3 occupies lower‑income, more rural regions; and Cluster 1 lies between them. The Household size vs. income plot shows that income is a key driver of separation, with Cluster 2 concentrated at higher incomes and Clusters 1 and 3 overlapping at lower incomes. The ellipses highlight the separation among the three groups across all pairwise combinations of the input variables. Because the plots are based on a random stratified sample, your results may look slightly different, but the overall cluster patterns will remain consistent.
Interpreting the Scatterplots
The scatterplots provide a visual confirmation of the cluster structure identified by PROC KCLUS. In the household size vs. regional density plot, Cluster 2 appears in high‑density areas, Cluster 3 in low‑density areas, and Cluster 1 falls between the two. The household income vs. regional density plot shows the same relationship: Cluster 2 corresponds to higher‑income, more urban regions; Cluster 3 corresponds to lower‑income, more rural regions; and Cluster 1 occupies the middle range.
The household size vs. income plot highlights income as a key driver of separation. Cluster 2 is concentrated at higher income levels, while Clusters 1 and 3 overlap at lower incomes. The ellipses summarize the spread of each cluster and help illustrate the separation across all pairwise combinations of the input variables.
Because the plots are based on a random stratified sample, the exact point patterns reflect the sample used here, but the overall cluster relationships are representative of the structure found in the full data.
Wrapping Up Part 1
This example shows how PROC KCLUS can be applied to a small, interpretable dataset to produce clear and meaningful clusters. The Census2000 data makes it easy to see how the algorithm behaves: the variables are straightforward, the clusters are easy to interpret, and the choice of inputs is simple. The same workflow applies to many other datasets, but real business data often requires more care in selecting variables, understanding correlations, and aligning the clustering goals with the broader analytic problem.
In Part 2, we’ll apply this workflow to a more complex business scenario where clustering supports downstream modeling and customer analysis. The data include many more predictors, and the clustering decisions are tied directly to a business objective. Please stay tuned for Part 2.
Links
Find more articles from SAS Global Enablement and Learning here.
Visit the Tips & Tricks page for setup guidance, demos, and practical examples that show how Copilot supports your workflows.
The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.