I wanted to perform above-ground biomass prediction with random forest algorithm. I am following a tutorial but I want to import my own dataset as a predictor. This is what I tried so far:
//adding the biomass map
var biomass = ee.Image('users/gulnihalkurtt/biomass');
var biomass_2020 = biomass.clip(boundary)
var biomass_20201 = biomass_2020.select('b1').rename('b2')
var visualization = {bands: ['b2'],};
Map.addLayer(biomass_20201, visualization, "biomass");
///////////////////
I wanted to rename the band as b2 so that I can include the raster in the algorithm like this:
// Bands to include in the classification
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B11', 'B12', 'VV_iqr', 'VH_iqr', 'elevation', 'slope','b1','b2'];
But I get an error which says: Line 238: Image.select: Pattern 'b2' did not match any bands.
Here is my full script:
// Load Sentinel-1 for the post-rainy season.
var S1_PRS = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterDate('2020-04-01', '2020-06-30')
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING'))
.filterBounds(boundary);
// Prepare inter-quartile range (IQR)
var S1_PRS_pc = S1_PRS.reduce(ee.Reducer.percentile([25,50,75]));
// Convert to natural units (linear units, which can be averaged)
var S1_PRS_pc = ee.Image(10).pow(S1_PRS_pc.divide(10));
var S1_PRS_pc_Feats = S1_PRS_pc.select(['VH_p50','VV_p50']).clip(boundary);
// Reproject to WGS 84 UTM zone 35s
var S1_PRS_pc_Feats = S1_PRS_pc_Feats.reproject({crs: 'EPSG:32735',scale: 100});
// Check projection information
print('Projection, crs, and crs_transform:', S1_PRS_pc_Feats.projection());
// Calculate inter-quartile range (IQR), a measure of Sentinel-1 backscatter variability
var PRS_VV_iqr = S1_PRS_pc_Feats.addBands((S1_PRS_pc.select('VV_p75').subtract(S1_PRS_pc.select('VV_p25'))).rename('VV_iqr'));
var PRS_VH_iqr = S1_PRS_pc_Feats.addBands((S1_PRS_pc.select('VH_p75').subtract(S1_PRS_pc.select('VH_p25'))).rename('VH_iqr'));
// Print the image to the console
print('Post-rainy Season VV IQR', PRS_VV_iqr);
// Print the image to the console
print('Post-rainy Season VV IQR', PRS_VH_iqr);
// Display S1 inter-quartile range imagery
Map.addLayer(PRS_VV_iqr.clip(boundary), {'bands': 'VV_iqr', min: 0,max: 0.1}, 'Sentinel-1 IW VV');
Map.addLayer( PRS_VH_iqr.clip(boundary), {'bands': 'VH_iqr', min: 0,max: 0.1}, 'Sentinel-1 IW VH');
/////////////////////
// Load Sentinel-2 spectral reflectance data.
var s2 = ee.ImageCollection('COPERNICUS/S2_SR');
// Create a function to mask clouds using the Sentinel-2 QA band.
function maskS2clouds(image) {
var qa = image.select('QA60');
// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = ee.Number(2).pow(10).int();
var cirrusBitMask = ee.Number(2).pow(11).int();
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
qa.bitwiseAnd(cirrusBitMask).eq(0));
// Return the masked and scaled data.
return image.updateMask(mask).divide(10000);
}
// Filter clouds from Sentinel-2 for a given period.
var composite = s2.filterDate('2020-04-01', '2020-06-30')
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
.map(maskS2clouds)
.select('B2', 'B3', 'B4','B5','B6','B7','B8','B11', 'B12');
// Reproject to WGS 84 UTM zone 35s
var S2_composite = composite.median().reproject({crs: 'EPSG:32635', scale: 100});
// Check projection information
print('Projection, crs, and crs_transform:', S2_composite.projection());
// Display a composite S2 imagery
Map.addLayer(S2_composite.clip(boundary), {bands: ['B11', 'B8', 'B3'], min: 0, max: 0.3});
//////////////////
// Load SRTM
var SRTM = ee.Image("USGS/SRTMGL1_003");
// Clip Elevation
var elevation = SRTM.clip(boundary);
// Reproject 'elevation' to WGS 84 UTM zone 35s
var elevation = elevation.reproject({crs: 'EPSG:32635',scale: 100});
// Check projection information
print('Projection, crs, and crs_transform:', elevation.projection());
// Derive slope from the SRTM
var slope = ee.Terrain.slope(SRTM).clip(boundary);
// Reproject 'slope' to WGS 84 UTM zone 35s
var slope = slope.reproject({crs: 'EPSG:32635',scale: 100});
// Check projection information
print('Projection, crs, and crs_transform:', slope.projection());
// Adding soil map
var soil = ee.Image('users/gulnihalkurtt/btg').clip(boundary);
//soil = soil.addBands ('b1')
var soil = soil.reproject({crs: 'EPSG:32635',scale: 100});
var visualization = {bands: ['b1'],};
Map.addLayer(soil, visualization, "Soil");
// Extracting the forest areas
var siniflama = ee.Image('users/gulnihalkurtt/siniflama_bmh1');
// Clip the land cover to the boundary
var LC_2020 = siniflama.clip(boundary);
// Extract forest areas from the land cover
var forest_mask = LC_2020.updateMask(
LC_2020.eq(77) // Only keep pixels where class equals 77
);
// Display forests only
var visualization = {bands: ['b1'],};
Map.addLayer(forest_mask, visualization, "Trees");
//adding the biomass map
var biomass = ee.Image('users/gulnihalkurtt/biomass');
var biomass_2020 = biomass.clip(boundary)
var biomass_20201 = biomass_2020.select('b1').rename('b2')
var visualization = {bands: ['b2'],};
Map.addLayer(biomass_20201, visualization, "biomass");
///////////////////
// Merge the predictor variables
var mergedCollection = S2_composite.addBands(PRS_VV_iqr.addBands(PRS_VH_iqr.addBands(elevation.addBands(slope.addBands(forest_mask.addBands(soil))))));
// Clip to the output image to Harare study area boundary.
var clippedmergedCollection = mergedCollection.clipToCollection(boundary);
print('clippedmergedCollection: ', clippedmergedCollection);
//Map.addLayer(clippedmergedCollection, {bands: ['B8', 'B4', 'B3'], max: 0.3}, 'mergedCollection');
// Bands to include in the classification
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B11', 'B12', 'VV_iqr', 'VH_iqr', 'elevation', 'slope','b1','b2'];
////////////////////
// Prepare training dataset
// More information at https://developers.google.com/earth-engine/datasets/catalog/LARSE_GEDI_GEDI04_B_002
var l4b = ee.Image('LARSE/GEDI/GEDI04_B_002');
var dataset = l4b.select('MU').clip(boundary);
Map.setCenter(28.8713,-18.4492, 12);
// Reproject to WGS 84 UTM zone 35s
var dataset = dataset.reproject({crs: 'EPSG:32635', scale: 200});
// Check projection information
print('Projection, crs, and crs_transform:', dataset.projection());
// Display the GEDI L4B dataset
Map.addLayer(dataset,
{min: 10, max: 250, palette: '440154,414387,2a788e,23a884,7ad151,fde725'},
'Mean Biomass');
// Sample the training points from the dataset
var points = dataset.sample({
region: boundary,
scale: 200,
numPixels: 1000,
geometries: true});
// Print and display the points derived from the GEDI L4B dataset
print(points.size());
print(points.limit(10));
Map.addLayer(points);
// Split training data into training and testing sets
// Add a random column (named random) and specify the seed value for repeatability
var datawithColumn = points.randomColumn('random', 300);
// Use 70% for training, 30% for validation
var split = 0.7;
var trainingData = datawithColumn.filter(ee.Filter.lt('random', split));
print('training data', trainingData);
var validationData = datawithColumn.filter(ee.Filter.gte('random', split));
print('validation data', validationData);
////////////////////
// Perform random forest regression
// Collect training data
var training = clippedmergedCollection.select(bands).sampleRegions({
collection: trainingData,
properties: ['MU'],
scale: 200 // Need to change the scale of training data to avoid the 'out of memory' problem
});
// Train a random forest classifier for regression
var classifier = ee.Classifier.smileRandomForest(150)
.setOutputMode('REGRESSION')
.train({
features: training,
classProperty: "MU",
inputProperties: bands
});
//Run the classification and clip it to the boundary
var regression = clippedmergedCollection.select(bands).classify(classifier, 'predicted').clip(boundary);
// Load and define a continuous palette
var palettes = require('users/gena/packages:palettes');
// Choose and define a palette
var palette = palettes.colorbrewer.YlGn[5];
// Display the input imagery and the regression classification.
// get dictionaries of min & max predicted value
var regressionMin = (regression.reduceRegion({
reducer: ee.Reducer.min(),
scale: 100,
crs: 'EPSG:32635',
geometry: boundary,
bestEffort: true,
tileScale: 16
}));
var regressionMax = (regression.reduceRegion({
reducer: ee.Reducer.max(),
scale: 100,
crs: 'EPSG:32635',
geometry: boundary,
bestEffort: true,
tileScale: 16
}));
// Add to map
var viz = {palette: palette, min: regressionMin.getNumber('predicted').getInfo(), max: regressionMax.getNumber('predicted').getInfo()};
Map.addLayer(regression, viz, 'Regression');
// Create the panel for the legend items.
var legend = ui.Panel({
style: {
position: 'bottom-left',
padding: '8px 15px'
}
});
// Create and add the legend title.
var legendTitle = ui.Label({
value: 'AGBD (Mg/ha)',
style: {
fontWeight: 'bold',
fontSize: '18px',
margin: '0 0 4px 0',
padding: '0'
}
});
legend.add(legendTitle);
// create the legend image
var lon = ee.Image.pixelLonLat().select('latitude');
var gradient = lon.multiply((viz.max-viz.min)/100.0).add(viz.min);
var legendImage = gradient.visualize(viz);
// create text on top of legend
var panel = ui.Panel({
widgets: [
ui.Label(viz['max'])
],
});
legend.add(panel);
// create thumbnail from the image
var thumbnail = ui.Thumbnail({
image: legendImage,
params: {bbox:'0,0,10,100', dimensions:'10x200'},
style: {padding: '1px', position: 'bottom-center'}
});
// add the thumbnail to the legend
legend.add(thumbnail);
// create text on top of legend
var panel = ui.Panel({
widgets: [
ui.Label(viz['min'])
],
});
legend.add(panel);
Map.add(legend);
// Zoom to the regression on the map
Map.centerObject(boundary, 11);
//////////////////////////
// Check model performance
// Get details of classifier
var classifier_details = classifier.explain();
// Explain the classifier with importance values
var variable_importance = ee.Feature(null, ee.Dictionary(classifier_details).get('importance'));
var chart =
ui.Chart.feature.byProperty(variable_importance)
.setChartType('ColumnChart')
.setOptions({
title: 'Random Forest Variable Importance',
legend: {position: 'none'},
hAxis: {title: 'Bands'},
vAxis: {title: 'Importance'}
});
// Plot a chart
print("Variable importance:", chart);
// Create model assessment statistics
// Get predicted regression points in same location as training data
var predictedTraining = regression.sampleRegions({collection:trainingData, geometries: true});
// Separate the observed (agbd_GEDI) and predicted (regression) properties
var sampleTraining = predictedTraining.select(['MU', 'predicted']);
// Create chart, print it
var chartTraining = ui.Chart.feature.byFeature(sampleTraining, 'MU', 'predicted')
.setChartType('ScatterChart').setOptions({
title: 'Predicted vs Observed - Training data ',
hAxis: {'title': 'observed'},
vAxis: {'title': 'predicted'},
pointSize: 3,
trendlines: { 0: {showR2: true, visibleInLegend: true} ,
1: {showR2: true, visibleInLegend: true}}});
print(chartTraining);
// Compute Root Mean Squared Error (RMSE)
// Get array of observation and prediction values
var observationTraining = ee.Array(sampleTraining.aggregate_array('MU'));
var predictionTraining = ee.Array(sampleTraining.aggregate_array('predicted'));
// Compute residuals
var residualsTraining = observationTraining.subtract(predictionTraining);
// Compute RMSE with equation and print the result
var rmseTraining = residualsTraining.pow(2).reduce('mean', [0]).sqrt();
print('Training RMSE', rmseTraining);
/////////////////////
//Perform validation
// Get predicted regression points in same location as validation data
var predictedValidation = regression.sampleRegions({collection:validationData, geometries: true});
// Separate the observed (MU) and predicted (regression) properties
var sampleValidation = predictedValidation.select(['MU', 'predicted']);
// Create chart and print it
var chartValidation = ui.Chart.feature.byFeature(sampleValidation, 'predicted', 'MU')
.setChartType('ScatterChart').setOptions({
title: 'Predicted vs Observed - Validation data',
hAxis: {'title': 'predicted'},
vAxis: {'title': 'observed'},
pointSize: 3,
trendlines: { 0: {showR2: true, visibleInLegend: true} ,
1: {showR2: true, visibleInLegend: true}}});
print(chartValidation);
// Compute RMSE
// Get array of observation and prediction values
var observationValidation = ee.Array(sampleValidation.aggregate_array('MU'));
var predictionValidation = ee.Array(sampleValidation.aggregate_array('predicted'));
// Compute residuals
var residualsValidation = observationValidation.subtract(predictionValidation);
// Compute RMSE with equation and print it
var rmseValidation = residualsValidation.pow(2).reduce('mean', [0]).sqrt();
print('Validation RMSE', rmseValidation);
//////////////////
// Export the image, specifying scale and region.
Export.image.toDrive({
image: regression,
description: 'Muf_AGBD_GEDI_2021',
scale: 20,
crs: 'EPSG:32635', // EPSG:32735 (WGS 84 UTM Zone 35S)
maxPixels: 6756353855,
region: boundary
});
Band names are case-sensitive, so you'll need to be consistent and use "B2" here (instead of "b2").