K-Means Land-Cover Classification in Google Earth Engine: A Sentinel-2 Workflow from Kaski, Nepal

In short

In Google Earth Engine, unsupervised land-cover mapping samples pixels from a Sentinel-2 composite, trains ee.Clusterer.wekaKMeans(k), clusters the image, and then labels each cluster by interpretation. Accuracy is assessed against independent reference points with a confusion matrix (errorMatrix) giving overall, producer's and user's accuracy. Bishal Neupane used this approach in Kaski, Nepal over 500+ hectares with six classes and a reported 85% accuracy.

Study area
Kaski district, Nepal (500+ ha, per CV)
Data
Sentinel-2 dry- and wet-season composites in GEE
Method
Exploratory K-Means clustering, six land-cover classes
Reported accuracy
85% across six classes (CV)
Indices
NDVI, NDWI, SAVI, GCI, PSRI

What the Kaski project did

Bishal Neupane's precision-agriculture analysis in Kaski district, Nepal, used Google Earth Engine (GEE) and Sentinel-2 imagery to map agricultural land with unsupervised K-Means clustering. According to his CV, the work covered more than 500 hectares, grouped the land into six land-cover classes with a reported 85% accuracy, and computed five vegetation indices for more than 200 farm plots. The methods page adds that he built dry-season and wet-season Sentinel-2 composites, derived NDVI, NDWI, SAVI, GCI and PSRI, and treated the K-Means result as exploratory: field validation is required before the map is used operationally. He also shared the work in a LinkedIn post.

That caveat is the right starting point for anyone copying the approach. K-Means is a quick, label-free way to see the structure of a landscape, but the clusters it returns are statistical groupings, not land-cover classes, until someone checks them against the ground.

Project elementAs stated on the site and CV
Platform and dataGoogle Earth Engine, Sentinel-2
CompositesDry season and wet season
IndicesNDVI, NDWI, SAVI, GCI, PSRI (five indices, 200+ farm plots)
MethodK-Means clustering (exploratory, unsupervised)
Area and classes500+ hectares, six land-cover classes
Reported accuracy85% across six classes (CV); field validation still required

Supervised vs unsupervised land-cover classification in GEE

GEE offers two families of tools. Classifiers (for example ee.Classifier.smileRandomForest) learn from labelled training points: you digitise examples of each class and the algorithm learns their spectral signatures. Clusterers (for example ee.Clusterer.wekaKMeans) need no labels; as the Earth Engine clustering guide puts it, unlike classifiers there is no input class value for a clusterer, and the output cluster IDs depend on the algorithm and inputs.

Unsupervised clustering suits a first look at a new area, situations with little or no reference data, and student projects where the aim is to understand spectral patterns before investing in field surveys. Supervised classification is usually preferred when a map must be defended, because the classes are defined in advance and validation is built into the design.

How K-Means works on satellite pixels

K-Means places k cluster centres in feature space (here, reflectance bands plus indices), assigns each pixel to the nearest centre, moves each centre to the mean of its pixels, and repeats until assignments stop changing. Three choices drive the result:

  • Features. Adding NDVI and NDWI to the raw bands helps separate vegetation and water. Seasonal composites help separate classes that look alike on one date, such as cropland that is green in the monsoon and bare in the dry season versus forest that stays green.
  • k. The number of clusters is your decision, not the algorithm's. Choosing six to match six intended classes is common, but a frequent practical approach is to run more clusters than classes and merge them afterwards.
  • Sampling. GEE trains the clusterer on a sample of pixels; the clustering guide warns that very large samples with many bands can run out of memory.

Step by step: K-Means land-cover classification in Google Earth Engine

The script below follows the pattern in the official clustering guide. It assumes you already have a cloud-masked median composite img, built as shown in the Sentinel-2 vegetation indices guide, from the harmonised Sentinel-2 surface reflectance collection.

// 'img' is a cloud-masked Sentinel-2 median composite scaled to reflectance, // built as in the vegetation-indices guide; 'aoi' is your study-area polygon. var ndvi = img.normalizedDifference(['B8', 'B4']).rename('NDVI'); var ndwi = img.normalizedDifference(['B3', 'B8']).rename('NDWI'); var input = img.select(['B2', 'B3', 'B4', 'B8', 'B11']).addBands([ndvi, ndwi]); // 1. Sample pixels to train the clusterer var training = input.sample({region: aoi, scale: 10, numPixels: 5000, seed: 42}); // 2. Train K-Means with k = 6 clusters var clusterer = ee.Clusterer.wekaKMeans(6).train(training); // 3. Assign every pixel to a cluster (output band: 'cluster', values 0-5) var clusters = input.cluster(clusterer); Map.centerObject(aoi, 13); Map.addLayer(clusters.randomVisualizer(), {}, 'K-Means clusters');

To mirror the dry- and wet-season design, build two composites and stack them (for example by renaming bands with a season suffix and combining them with addBands) before sampling, so each pixel carries both seasons' spectral information.

Turning clusters into land-cover classes

The clusters come out as integers 0 to 5 in no meaningful order. Labelling them is an interpretation step: overlay each cluster on high-resolution imagery, compare with field knowledge, and note its typical NDVI and NDWI. Clusters that clearly represent the same thing can be merged; a cluster that mixes two land covers is a sign that k, the features or the season choice needs revisiting. Once labelled, remap the cluster IDs to class codes.

How is classification accuracy assessed?

The CV reports 85% accuracy for the Kaski classification but does not describe the assessment procedure, so this section explains standard practice rather than the exact steps used in that project. Accuracy assessment compares the map with independent reference data, meaning points whose true class is known from field visits, GPS-tagged observations or careful interpretation of higher-resolution imagery, and which were not used to build or label the map.

// 4. Label clusters after visual inspection (this mapping is only an example) var classified = clusters.remap([0, 1, 2, 3, 4, 5], [3, 1, 5, 2, 4, 6]) .rename('classification'); // 5. Accuracy assessment against independent reference points // refPoints: FeatureCollection with an integer property 'class' (1-6) var validated = classified.sampleRegions({collection: refPoints, properties: ['class'], scale: 10}); var cm = validated.errorMatrix('class', 'classification'); print('Confusion matrix', cm); print('Overall accuracy', cm.accuracy()); print('Kappa', cm.kappa()); print('Producer accuracy', cm.producersAccuracy()); print('User (consumer) accuracy', cm.consumersAccuracy());

The confusion matrix cross-tabulates reference class against mapped class. From it come:

MetricWhat it tells you
Overall accuracyShare of all reference points mapped to the correct class
Producer's accuracyFor each true class, how much of it the map captured (omission error = 1 − producer's accuracy)
User's (consumer's) accuracyFor each mapped class, how often it is correct on the ground (commission error = 1 − user's accuracy)
KappaAgreement adjusted for chance; widely reported, though many authors now prefer reporting the full matrix with per-class accuracies

The Earth Engine classification guide makes a point worth repeating: accuracy estimated from training data is an overestimate. Validation points must be held out, for example by splitting a sample roughly 70/30 with randomColumn() for supervised work, or by collecting a separate set of field points for an unsupervised map. Report per-class accuracies as well as the overall figure, because a high overall number can hide a poorly mapped minority class such as small water bodies or settlements.

Limitations to keep in mind

  • Kaski's terraced, mixed-use landscape produces many mixed pixels at 10–20 m resolution, which limits how finely classes can be separated.
  • Monsoon cloud cover restricts usable optical scenes in the wet season, so wet-season composites may draw on few clear observations.
  • Cluster labels are subjective; another analyst may label them differently. Documenting the labelling rules makes the map reproducible.
  • As the methods page says, an exploratory map needs field validation before it supports farm-level decisions.

For how clustering fits with GIS and other machine-learning steps, see GIS, remote sensing and ML as one system, and for water-focused analysis in the same region, the Pokhara NDWI guide. Supervisors or collaborators working on land-cover mapping in Nepal's hills are welcome to get in touch through the contact page.

Frequently asked questions

How do I run K-Means classification in Google Earth Engine?

Build a cloud-free composite, sample pixels with image.sample(), train a clusterer with ee.Clusterer.wekaKMeans(k).train(sample), then apply it with image.cluster(clusterer). The result is a single 'cluster' band with integer IDs. Those IDs carry no class meaning until you inspect each cluster and remap it to a land-cover class.

What is the difference between supervised and unsupervised classification?

Supervised classification learns from labelled training points for each class, for example with Random Forest. Unsupervised classification, such as K-Means, groups pixels by spectral similarity without labels, and the analyst assigns meaning to the groups afterwards. Unsupervised methods are quick for exploration; supervised methods are usually preferred when a map must be formally validated.

Can an unsupervised K-Means map have an accuracy figure?

Yes. Once clusters are labelled as land-cover classes, the map can be compared with independent reference points exactly like a supervised map, using a confusion matrix. The reference points must not be the ones used to interpret or label the clusters, otherwise the accuracy estimate will be inflated.

How do I calculate overall accuracy and kappa in GEE?

Sample the classified image at reference points with sampleRegions(), keeping the true class property. Call errorMatrix('trueClass', 'classification') on the result to get an ee.ConfusionMatrix, then use accuracy() for overall accuracy, kappa() for kappa, producersAccuracy() for omission-based accuracy and consumersAccuracy() for user's accuracy per class.

How many clusters should I choose for K-Means land cover?

There is no automatic answer. A common approach is to start with the number of classes you need, inspect the clusters, and increase k if clusters mix different land covers, merging similar clusters afterwards. Using seasonal composites and indices such as NDVI and NDWI as features often separates classes better than adding more clusters.

Sources