2

I use the .reduceRegion({reducer: ee.Reducer.sum().group(1)}) option to get the sum of the areas in my image per class. The only problem is that some classes are not present in certain regions. The output of this .reduceRegion leaves out those classes, whereas I would like the output to still include the class and says that the sum is 0. Does anyone know how to get this?

My script can be found here: https://code.earthengine.google.com/908693bb53ad9596b67b96574286d1d8

var province = 'Bukidnon'
var nClusters = 8

var fromList = ee.FeatureCollection("FAO/GAUL/2015/level2");
var filter = ee.Filter.inList('ADM2_NAME', [province]);
var filteredArea = fromList.filter(filter);
var roi=filteredArea.geometry();
Map.centerObject(roi)
var table = table.filter(ee.Filter.eq('ADM2_EN', province))

var startDateStr = '2018-06-01'
var endDateStr = '2019-06-01'
var startDate = ee.Date(startDateStr);
var endDate =  ee.Date(endDateStr);
var startEnd = ee.String(startDateStr).cat(ee.String(endDateStr))
var sentinel1_vh = ee.ImageCollection('COPERNICUS/S1_GRD')
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
  .select('VH')
  .filter(ee.Filter.eq('instrumentMode', 'IW'))
  .filter(ee.Filter.eq('resolution_meters', 10))
  //.filter(ee.Filter.eq('orbitProperties_pass', 'DESCENDING'))
  .filter(ee.Filter.date(startDate, endDate))
  .filter(ee.Filter.bounds(roi));

// For month
var month = 1;
// Calculating number of intervals
var months = endDate.difference(startDate,'month').divide(month).toInt();
// Generating a sequence 
var sequence = ee.List.sequence(0, months); 

var sequence_s1 = sequence.map(function(num){
    num = ee.Number(num);
    var Start_interval = startDate.advance(num.multiply(month), 'month');
    var End_interval = startDate.advance(num.add(1).multiply(month), 'month');
    var subset = sentinel1_vh.filterDate(Start_interval,End_interval);
    return subset.median().set('system:time_start',Start_interval);
});

var byMonthYearS1 = (ee.ImageCollection.fromImages(sequence_s1)).filter(ee.Filter.date(startDate, endDate));
var multibands1 = byMonthYearS1.toBands().clip(roi);

// Reset the bandnames
var namess1 = multibands1.bandNames();
// rename the bandnames 
var nMonthss1 =(namess1.length()).subtract(1) ;

var pertamas1=sentinel1_vh.first();
var systimes1=pertamas1.get('system:time_start');
var startDates1 =(ee.Date(systimes1));
// get a list of time strings to pass into a dictionary later on
var monLists1 = ee.List.sequence(0, nMonthss1).map(function (n) {
  return startDates1.advance(n, 'month').format('yyyy-MM');
})
var multibands1 = multibands1.rename(monLists1).clip(roi);//
var combinedband = multibands1;

// ********************************************
// unsupervised learning / clustering
// ********************************************

var training = combinedband.sample({
  region: roi,
  scale: 10,
  numPixels: 2000,
  tileScale:8
});


var clusterer = ee.Clusterer.wekaKMeans(nClusters).train({
  features:training
});

// Cluster the input using the trained clusterer.
var result_cluster =combinedband.cluster(clusterer).byte();
var clusters = ee.List.sequence(0, ee.Number(nClusters).subtract(1)); 
var values0 = ee.List.sequence(1, nClusters)
               
var remapped_cluster = result_cluster.remap(clusters, values0).clip(roi);
var remapped_cluster = remapped_cluster.rename('class')
var rice_mask_multi=multibands1.addBands(remapped_cluster);

//////////////////////////////////////////////
///// supervised learning
//////////////////////////////////////////////

// use all 24 months as training data
var bands = monLists1
var rice_mask_multi = rice_mask_multi.cast({'class': 'int64'})
// use 2000 data points as training set
var training_set = rice_mask_multi.stratifiedSample({
  region: roi,
  classBand: 'class',
  scale: 100,
  geometries: true,
  numPoints: 3200,
  classValues: [1, 2, 3, 4, 5, 6, 7, 8],
  classPoints: [400, 400, 400, 400, 400, 400, 400, 400],
  seed: 0
});

var combinedband_train = combinedband;
// Get the values for all pixels in each polygon in the training.
var training = combinedband_train.sampleRegions({
  // Get the sample from the polygons FeatureCollection.
  collection: training_set,
  // Keep this list of properties from the polygons.
  properties: ['class'],
  // Set the scale to get Landsat pixels in the polygons.
  scale: 100
});

// Create an SVM classifier with custom parameters.
var classifier = ee.Classifier.libsvm({
  kernelType: 'RBF',
//  cost: 1.5
//  gamma: 0.5
});

// Train the classifier.
var trained = classifier.train(training, 'class', bands);
// Classify the image.
var classified = combinedband.classify(trained);

var n = table.size();

var getKey = function(number){
  return ee.Feature(table.toList(n).get(number)).get('ADM3_EN')
}
var list = ee.List.sequence(0, n.subtract(1));
var keys = list.map(getKey)

// var dic = ee.Dictionary.fromLists(keys, table.geometry().coordinates())
var getRiceMunActual = function(index){
  var geo_mun = ee.Feature(table.toList(120).get(index)).geometry().dissolve();
  var roi_mun_a = rice_mask_multi.clip(geo_mun)
  var rice_actual = ee.Image.pixelArea().divide(1000000).addBands(remapped_cluster).reduceRegion({
  reducer: ee.Reducer.sum().group(1),
  geometry: roi_mun_a.geometry(),
  scale: 100,
  maxPixels: 1e9
});
  return rice_actual
}

var riceAreasActual = list.map(getRiceMunActual)
print(riceAreasActual)

It's about the last part of the code (from line 135 onwards). I would like that all elements of the object riceAreasActual are fo the same length (8 in this case), whereas you can see now that some are of length 7 (index, 5, 6, 9, 10) since in those regions the class with label 2 is not present.

1 Answer 1

2

Convert the groups to a dictionary and combine the result for each region with a dictionary of defaults.

// Create a dictionary of defaults.
var defaults = ee.Dictionary(ee.List.sequence(1, 8).map(function(n) {
  return [ee.Number(n).format("%d"), 0]
}).flatten())

// Convert a grouped reducer output to a dictionary
var convert = function(groups) {
  return ee.Dictionary(ee.List(groups).map(function(g) {
    g = ee.Dictionary(g)
    return [g.getNumber('group').format("%d"), g.get('sum')]
  }).flatten()).combine(defaults, false)
}

https://code.earthengine.google.com/987e82b3f1fc8b0b6bd282aa10eab5ef

1
  • Super, thank you so much! Commented Dec 7, 2021 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.