סיווג בפיקוח

החבילה Classifier מטפלת בסיווג מבוקר באמצעות אלגוריתמים מסורתיים של למידת מכונה שפועלים ב-Earth Engine. המסווגים האלה כוללים את CART, ‏ RandomForest,‏ NaiveBayes ו-SVM. תהליך העבודה הכללי לסיווג הוא:

  1. איסוף נתוני אימון. אוספים מאפיינים שיש להם נכס שבו מאוחסנת תווית הסיווג הידועה, ונכסים שבהם מאוחסנים ערכים מספריים של המנבאים.
  2. יוצרים מופע של מסווג. מגדירים את הפרמטרים שלו, אם צריך.
  3. מאמנים את המסווג באמצעות נתוני האימון.
  4. סיווג של תמונה או אוסף מאפיינים.
  5. הערכת שגיאת הסיווג באמצעות נתוני אימות עצמאיים.

נתוני האימון הם FeatureCollection עם מאפיין שבו מאוחסנת תווית הסיווג ומאפיינים שבהם מאוחסנים משתני החיזוי. תוויות הסיווג צריכות להיות מספרים שלמים עוקבים, החל מ-0. במקרה הצורך, אפשר להשתמש ב-remap() כדי להמיר ערכי מחלקות למספרים שלמים עוקבים. המשתנים המנבאים צריכים להיות מספריים.

נתוני האימון ו/או האימות יכולים להגיע ממגוון מקורות. כדי לאסוף נתוני אימון באופן אינטראקטיבי ב-Earth Engine, אפשר להשתמש בכלי השרטוט הגיאומטריים (ראו את הקטע "כלי גיאומטריה" בדף של עורך הקוד). לחלופין, אפשר לייבא נתוני אימון מוגדרים מראש מנכס טבלה של Earth Engine (פרטים נוספים זמינים בדף ייבוא נתוני טבלה). מקבלים מסווג מאחד מהבנאים ב-ee.Classifier. מאמנים את המסווג באמצעות classifier.train(). סיווג של Image או FeatureCollection באמצעות classify(). בדוגמה הבאה נעשה שימוש בסיווג של עצי סיווג ורגרסיה (CART) (Breiman et al. 1984) כדי לחזות שלוש קבוצות פשוטות:

Code Editor (JavaScript)

// Define a function that scales and masks Landsat 8 surface reflectance images.
function prepSrL8(image) {
  // Develop masks for unwanted pixels (fill, cloud, cloud shadow).
  var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
  var saturationMask = image.select('QA_RADSAT').eq(0);

  // Apply the scaling factors to the appropriate bands.
  var getFactorImg = function(factorNames) {
    var factorList = image.toDictionary().select(factorNames).values();
    return ee.Image.constant(factorList);
  };
  var scaleImg = getFactorImg([
    'REFLECTANCE_MULT_BAND_.|TEMPERATURE_MULT_BAND_ST_B10']);
  var offsetImg = getFactorImg([
    'REFLECTANCE_ADD_BAND_.|TEMPERATURE_ADD_BAND_ST_B10']);
  var scaled = image.select('SR_B.|ST_B10').multiply(scaleImg).add(offsetImg);

  // Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, null, true)
    .updateMask(qaMask).updateMask(saturationMask);
}

// Make a cloud-free Landsat 8 surface reflectance composite.
var image = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2021-03-01', '2021-07-01')
  .map(prepSrL8)
  .median();

// Use these bands for prediction.
var bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5',
             'SR_B6', 'SR_B7', 'ST_B10'];

// Load training points. The numeric property 'class' stores known labels.
var points = ee.FeatureCollection('GOOGLE/EE/DEMOS/demo_landcover_labels');

// This property stores the land cover labels as consecutive
// integers starting from zero.
var label = 'landcover';

// Overlay the points on the imagery to get training.
var training = image.select(bands).sampleRegions({
  collection: points,
  properties: [label],
  scale: 30
});

// Train a CART classifier with default parameters.
var trained = ee.Classifier.smileCart().train(training, label, bands);

// Classify the image with the same bands used for training.
var classified = image.select(bands).classify(trained);

// Display the inputs and the results.
Map.setCenter(-122.0877, 37.7880, 11);
Map.addLayer(image,
             {bands: ['SR_B4', 'SR_B3', 'SR_B2'], min: 0, max: 0.25},
             'image');
Map.addLayer(classified,
             {min: 0, max: 2, palette: ['orange', 'green', 'blue']},
             'classification');

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

# Define a function that scales and masks Landsat 8 surface reflectance images.
def prep_sr_l8(image):
  """Scales and masks Landsat 8 surface reflectance images."""
  # Develop masks for unwanted pixels (fill, cloud, cloud shadow).
  qa_mask = image.select('QA_PIXEL').bitwiseAnd(0b11111).eq(0)
  saturation_mask = image.select('QA_RADSAT').eq(0)

  # Apply the scaling factors to the appropriate bands.
  def _get_factor_img(factor_names):
    factor_list = image.toDictionary().select(factor_names).values()
    return ee.Image.constant(factor_list)

  scale_img = _get_factor_img([
      'REFLECTANCE_MULT_BAND_.|TEMPERATURE_MULT_BAND_ST_B10'])
  offset_img = _get_factor_img([
      'REFLECTANCE_ADD_BAND_.|TEMPERATURE_ADD_BAND_ST_B10'])
  scaled = image.select('SR_B.|ST_B10').multiply(scale_img).add(offset_img)

  # Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, None, True).updateMask(
      qa_mask).updateMask(saturation_mask)


# Make a cloud-free Landsat 8 surface reflectance composite.
l8_image = (
    ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterDate('2021-03-01', '2021-07-01')
    .map(prep_sr_l8)
    .median())

# Use these bands for prediction.
bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', 'ST_B10']

# Load training points. The numeric property 'class' stores known labels.
points = ee.FeatureCollection('GOOGLE/EE/DEMOS/demo_landcover_labels')

# This property stores the land cover labels as consecutive
# integers starting from zero.
label = 'landcover'

# Overlay the points on the imagery to get training.
training = l8_image.select(bands).sampleRegions(
    collection=points, properties=[label], scale=30
)

# Train a CART classifier with default parameters.
trained = ee.Classifier.smileCart().train(training, label, bands)

# Classify the image with the same bands used for training.
classified = l8_image.select(bands).classify(trained)

# Display the inputs and the results.
m = geemap.Map()
m.set_center(-122.0877, 37.7880, 11)
m.add_layer(
    l8_image,
    {'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 0, 'max': 0.25},
    'image',
)
m.add_layer(
    classified,
    {'min': 0, 'max': 2, 'palette': ['orange', 'green', 'blue']},
    'classification',
)
m

בדוגמה הזו, נקודות האימון בטבלה מאחסנות רק את תווית הסיווג. שימו לב שמאפיין האימון ('landcover') מאחסן מספרים שלמים עוקבים שמתחילים ב-0 (אם צריך, השתמשו ב-remap() בטבלה כדי להפוך את תוויות הסיווג למספרים שלמים עוקבים שמתחילים ב-0). שימו לב גם לשימוש ב-image.sampleRegions() כדי להכניס את המנבאים לטבלה וליצור מערך נתונים לאימון. כדי לאמן את המסווג, מציינים את השם של מאפיין תווית הסיווג ורשימה של מאפיינים בטבלת האימון שבהם המסווג צריך להשתמש כגורמים חזויים. המספר והסדר של הרצועות בתמונה שרוצים לסווג חייבים להתאים בדיוק לסדר של רשימת המאפיינים שסופקה ל-classifier.train(). צריך להשתמש ב-image.select() כדי לוודא שהסכימה של המסווג תואמת לתמונה.

אם נתוני האימון הם פוליגונים שמייצגים אזורים הומוגניים, כל פיקסל בכל פוליגון הוא נקודת אימון. אפשר להשתמש במצולעים לאימון, כמו בדוגמה הבאה:

Code Editor (JavaScript)

// Define a function that scales and masks Landsat 8 surface reflectance images.
function prepSrL8(image) {
  // Develop masks for unwanted pixels (fill, cloud, cloud shadow).
  var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
  var saturationMask = image.select('QA_RADSAT').eq(0);

  // Apply the scaling factors to the appropriate bands.
  var getFactorImg = function(factorNames) {
    var factorList = image.toDictionary().select(factorNames).values();
    return ee.Image.constant(factorList);
  };
  var scaleImg = getFactorImg([
    'REFLECTANCE_MULT_BAND_.|TEMPERATURE_MULT_BAND_ST_B10']);
  var offsetImg = getFactorImg([
    'REFLECTANCE_ADD_BAND_.|TEMPERATURE_ADD_BAND_ST_B10']);
  var scaled = image.select('SR_B.|ST_B10').multiply(scaleImg).add(offsetImg);

  // Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, null, true)
    .updateMask(qaMask).updateMask(saturationMask);
}

// Make a cloud-free Landsat 8 surface reflectance composite.
var image = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2018-01-01', '2019-01-01')
  .map(prepSrL8)
  .median();

// Use these bands for prediction.
var bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5',
             'SR_B6', 'SR_B7'];

// Manually created polygons.
var forest1 = ee.Geometry.Rectangle(-63.0187, -9.3958, -62.9793, -9.3443);
var forest2 = ee.Geometry.Rectangle(-62.8145, -9.206, -62.7688, -9.1735);
var nonForest1 = ee.Geometry.Rectangle(-62.8161, -9.5001, -62.7921, -9.4486);
var nonForest2 = ee.Geometry.Rectangle(-62.6788, -9.044, -62.6459, -8.9986);

// Make a FeatureCollection from the hand-made geometries.
var polygons = ee.FeatureCollection([
  ee.Feature(nonForest1, {'class': 0}),
  ee.Feature(nonForest2, {'class': 0}),
  ee.Feature(forest1, {'class': 1}),
  ee.Feature(forest2, {'class': 1}),
]);

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

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

// Train the classifier.
var trained = classifier.train(training, 'class', bands);

// Classify the image.
var classified = image.classify(trained);

// Display the classification result and the input image.
Map.setCenter(-62.836, -9.2399, 9);
Map.addLayer(image,
             {bands: ['SR_B4', 'SR_B3', 'SR_B2'], min: 0, max: 0.25},
             'image');
Map.addLayer(polygons, {color: 'yellow'}, 'training polygons');
Map.addLayer(classified,
             {min: 0, max: 1, palette: ['orange', 'green']},
             'deforestation');

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

# Define a function that scales and masks Landsat 8 surface reflectance images.
def prep_sr_l8(image):
  # Develop masks for unwanted pixels (fill, cloud, cloud shadow).
  qa_mask = image.select('QA_PIXEL').bitwiseAnd(0b11111).eq(0)
  saturation_mask = image.select('QA_RADSAT').eq(0)

  # Apply the scaling factors to the appropriate bands.
  def _get_factor_img(factor_names):
    factor_list = image.toDictionary().select(factor_names).values()
    return ee.Image.constant(factor_list)
  scale_img = _get_factor_img([
      'REFLECTANCE_MULT_BAND_.|TEMPERATURE_MULT_BAND_ST_B10'])
  offset_img = _get_factor_img([
      'REFLECTANCE_ADD_BAND_.|TEMPERATURE_ADD_BAND_ST_B10'])
  scaled = image.select('SR_B.|ST_B10').multiply(scale_img).add(offset_img)

  # Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, None, True).updateMask(
      qa_mask).updateMask(saturation_mask)


# Make a cloud-free Landsat 8 surface reflectance composite.
l8_image = (
    ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterDate('2018-01-01', '2019-01-01')
    .map(prep_sr_l8)
    .median())

# Use these bands for prediction.
bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']

# Manually created polygons.
forest1 = ee.Geometry.Rectangle(-63.0187, -9.3958, -62.9793, -9.3443)
forest2 = ee.Geometry.Rectangle(-62.8145, -9.206, -62.7688, -9.1735)
non_forest1 = ee.Geometry.Rectangle(-62.8161, -9.5001, -62.7921, -9.4486)
non_forest2 = ee.Geometry.Rectangle(-62.6788, -9.044, -62.6459, -8.9986)

# Make a FeatureCollection from the hand-made geometries.
polygons = ee.FeatureCollection([
    ee.Feature(non_forest1, {'class': 0}),
    ee.Feature(non_forest1, {'class': 0}),
    ee.Feature(forest1, {'class': 1}),
    ee.Feature(forest2, {'class': 1}),
])

# Get the values for all pixels in each polygon in the training.
training = l8_image.sampleRegions(
    # Get the sample from the polygons FeatureCollection.
    collection=polygons,
    # Keep this list of properties from the polygons.
    properties=['class'],
    # Set the scale to get Landsat pixels in the polygons.
    scale=30,
)

# Create an SVM classifier with custom parameters.
classifier = ee.Classifier.libsvm(kernelType='RBF', gamma=0.5, cost=10)

# Train the classifier.
trained = classifier.train(training, 'class', bands)

# Classify the image.
classified = l8_image.classify(trained)

# Display the classification result and the input image.
m = geemap.Map()
m.set_center(-62.836, -9.2399, 9)
m.add_layer(
    l8_image,
    {'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 0, 'max': 0.25},
    'image',
)
m.add_layer(polygons, {'color': 'yellow'}, 'training polygons')
m.add_layer(
    classified,
    {'min': 0, 'max': 1, 'palette': ['orange', 'green']},
    'deforestation',
)
m

בדוגמה הזו נעשה שימוש בסיווג של מכונת וקטורים תומכים (SVM) (Burges 1998). שימו לב שה-SVM מוגדר עם קבוצה של פרמטרים מותאמים אישית. בלי מידע אפריורי על האופי הפיזי של בעיית החיזוי, הפרמטרים האופטימליים לא ידועים. במאמר של Hsu et al. (2003) יש מדריך כללי לבחירת פרמטרים ל-SVM.

מצבי פלט של מסווגים

השיטה ee.Classifier.setOutputMode() קובעת את הפורמט של תוצאות הסיווג בפיקוח, ומאפשרת להגדיר את המבנה של הפלט בכמה דרכים שונות:

  • ‫CLASSIFICATION (ברירת מחדל): הפלט הוא מספר הסיווג.
  • ‫REGRESSION: הפלט הוא תוצאה של רגרסיה רגילה.
  • ‫PROBABILITY: הפלט הוא ההסתברות שהסיווג נכון.
  • ‫MULTIPROBABILITY: הפלט הוא מערך של הסתברויות לכך שכל מחלקה נכונה, בסדר שבו המחלקות מופיעות.
  • ‫RAW: הפלט הוא מערך של הייצוג הפנימי של תהליך הסיווג. לדוגמה, ההצבעות הגולמיות במודלים של עצי החלטות מרובים.
  • ‫RAW_REGRESSION: הפלט הוא מערך של הייצוג הפנימי של תהליך הרגרסיה. לדוגמה, החיזויים הגולמיים של כמה עצי רגרסיה.

התמיכה במצבי הפלט האלה משתנה. בטבלה הבאה מפורטים המצבים הנתמכים בכל מסווג.

מסווג סיווג רגרסיה הסתברות MULTIPROBABILITY RAW RAW_REGRESSION
ee.Classifier.amnhMaxent
ee.Classifier.minimumDistance
ee.Classifier.smileCart
ee.Classifier.smileGradientTreeBoost
ee.Classifier.smileKNN
ee.Classifier.smileNaiveBayes
ee.Classifier.smileRandomForest
ee.Classifier.libsvm C_SVC
‫ee.Classifier.libsvm NU_SVC
ee.Classifier.libsvm ONE_CLASS
ee.Classifier.libsvm EPSILON_SVR
‫ee.Classifier.libsvm NU_SVR

כדי להגדיר את פורמט הפלט, צריך להשתמש ב-setOutputMode() לפני שמאמנים מסווג. לדוגמה, אפשר להגדיר את מסווג ה-SVM בבלוק הקוד הקודם כך שיפיק הסתברות במקום תוויות הסיווג שמוגדרות כברירת מחדל:

Code Editor (JavaScript)

var classifier = ee.Classifier.libsvm({
  kernelType: 'RBF',
  gamma: 0.5,
  cost: 10
}).setOutputMode('PROBABILITY');

var trained = classifier.train(training, 'class', bands);

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

classifier = ee.Classifier.libsvm(
    kernelType='RBF', gamma=0.5, cost=10
).setOutputMode('PROBABILITY')

trained = classifier.train(training, 'class', bands)

בדיקת דיוק

כדי להעריך את הדיוק של מסווג, משתמשים בConfusionMatrix (Stehman 1997). בדוגמה הבאה נעשה שימוש ב-sample() כדי ליצור נתוני אימון ואימות מתמונת רפרנס של MODIS, ומשווים בין מטריצות טעויות שמייצגות את דיוק האימון והאימות:

Code Editor (JavaScript)

// Define a region of interest.
var roi = ee.Geometry.BBox(-122.93, 36.99, -121.20, 38.16);

// Define a function that scales and masks Landsat 8 surface reflectance images.
function prepSrL8(image) {
  // Develop masks for unwanted pixels (fill, cloud, cloud shadow).
  var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
  var saturationMask = image.select('QA_RADSAT').eq(0);

  // Apply the scaling factors to the appropriate bands.
  var getFactorImg = function(factorNames) {
    var factorList = image.toDictionary().select(factorNames).values();
    return ee.Image.constant(factorList);
  };
  var scaleImg = getFactorImg([
    'REFLECTANCE_MULT_BAND_.|TEMPERATURE_MULT_BAND_ST_B10']);
  var offsetImg = getFactorImg([
    'REFLECTANCE_ADD_BAND_.|TEMPERATURE_ADD_BAND_ST_B10']);
  var scaled = image.select('SR_B.|ST_B10').multiply(scaleImg).add(offsetImg);

  // Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, null, true)
    .updateMask(qaMask).updateMask(saturationMask);
}

// Make a cloud-free Landsat 8 surface reflectance composite.
var input = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterBounds(roi)
    .filterDate('2020-03-01', '2020-07-01')
    .map(prepSrL8)
    .median()
    .setDefaultProjection('EPSG:4326', null, 30)
    .select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']);

// Use MODIS land cover, IGBP classification, for training.
var modis = ee.Image('MODIS/061/MCD12Q1/2020_01_01')
    .select('LC_Type1');

// Sample the input imagery to get a FeatureCollection of training data.
var training = input.addBands(modis).sample({
  region: roi,
  numPixels: 5000,
  seed: 0
});

// Make a Random Forest classifier and train it.
var classifier = ee.Classifier.smileRandomForest(10)
    .train({
      features: training,
      classProperty: 'LC_Type1',
      inputProperties: ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']
    });

// Classify the input imagery.
var classified = input.classify(classifier);

// Get a confusion matrix representing resubstitution accuracy.
var trainAccuracy = classifier.confusionMatrix();
print('Resubstitution error matrix: ', trainAccuracy);
print('Training overall accuracy: ', trainAccuracy.accuracy());

// Sample the input with a different random seed to get validation data.
var validation = input.addBands(modis).sample({
  region: roi,
  numPixels: 5000,
  seed: 1
  // Filter the result to get rid of any null pixels.
}).filter(ee.Filter.notNull(input.bandNames()));

// Classify the validation data.
var validated = validation.classify(classifier);

// Get a confusion matrix representing expected accuracy.
var testAccuracy = validated.errorMatrix('LC_Type1', 'classification');
print('Validation error matrix: ', testAccuracy);
print('Validation overall accuracy: ', testAccuracy.accuracy());

// Define a palette for the IGBP classification.
var igbpPalette = [
  '152106', '225129', '369b47', '30eb5b', '387242', // forest
  '6a2325', 'c3aa69', 'b76031', 'd9903d', '91af40',  // shrub, grass
  '111149', // wetlands
  'cdb33b', // croplands
  'cc0013', // urban
  '33280d', // crop mosaic
  'd7cdcc', // snow and ice
  'f7e084', // barren
  'aec3d4'  // water
];

// Display the input and the classification.
Map.centerObject(roi, 10);
Map.addLayer(input.clip(roi),
             {bands: ['SR_B4', 'SR_B3', 'SR_B2'], min: 0, max: 0.25},
             'landsat');
Map.addLayer(classified.clip(roi),
             {palette: igbpPalette, min: 1, max: 17},
             'classification');

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

# Define a region of interest.
roi = ee.Geometry.BBox(-122.93, 36.99, -121.20, 38.16)

# Define a function that scales and masks Landsat 8 surface reflectance images.
def prep_sr_l8(image):
  """Scales and masks Landsat 8 surface reflectance images."""
  # Develop masks for unwanted pixels (fill, cloud, cloud shadow).
  qa_mask = image.select('QA_PIXEL').bitwiseAnd(0b1111).eq(0)
  saturation_mask = image.select('QA_RADSAT').eq(0)

  # Apply the scaling factors to the appropriate bands.
  def _get_factor_img(factor_names):
    factor_list = image.toDictionary().select(factor_names).values()
    return ee.Image.constant(factor_list)

  scale_img = _get_factor_img([
      'REFLECTANCE_MULT_BAND_.|TEMPERATURE_MULT_BAND_ST_B10'])
  offset_img = _get_factor_img([
      'REFLECTANCE_ADD_BAND_.|TEMPERATURE_ADD_BAND_ST_B10'])
  scaled = image.select('SR_B.|ST_B10').multiply(scale_img).add(offset_img)

  # Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, None, True).updateMask(
      qa_mask).updateMask(saturation_mask)


# Make a cloud-free Landsat 8 surface reflectance composite.
input_image = (
    ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterBounds(roi)
    .filterDate('2020-03-01', '2020-07-01')
    .map(prep_sr_l8)
    .median()
    .setDefaultProjection('EPSG:4326', None, 30)
    .select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'])
)

# Use MODIS land cover, IGBP classification, for training.
modis = ee.Image('MODIS/061/MCD12Q1/2020_01_01').select('LC_Type1')

# Sample the input imagery to get a FeatureCollection of training data.
training = input_image.addBands(modis).sample(
    region=roi, numPixels=5000, seed=0
)

# Make a Random Forest classifier and train it.
classifier = ee.Classifier.smileRandomForest(10).train(
    features=training,
    classProperty='LC_Type1',
    inputProperties=['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],
)

# Classify the input imagery.
classified = input_image.classify(classifier)

# Get a confusion matrix representing resubstitution accuracy.
train_accuracy = classifier.confusionMatrix()
display('Resubstitution error matrix:', train_accuracy)
display('Training overall accuracy:', train_accuracy.accuracy())

# Sample the input with a different random seed to get validation data.
validation = (
    input_image.addBands(modis)
    .sample(
        region=roi,
        numPixels=5000,
        seed=1,
        # Filter the result to get rid of any null pixels.
    )
    .filter(ee.Filter.notNull(input_image.bandNames()))
)

# Classify the validation data.
validated = validation.classify(classifier)

# Get a confusion matrix representing expected accuracy.
test_accuracy = validated.errorMatrix('LC_Type1', 'classification')
display('Validation error matrix:', test_accuracy)
display('Validation overall accuracy:', test_accuracy.accuracy())

# Define a palette for the IGBP classification.
igbp_palette = [
    '152106', '225129', '369b47', '30eb5b', '387242',  # forest
    '6a2325', 'c3aa69', 'b76031', 'd9903d', '91af40',  # shrub, grass
    '111149',  # wetlands
    'cdb33b',  # croplands
    'cc0013',  # urban
    '33280d',  # crop mosaic
    'd7cdcc',  # snow and ice
    'f7e084',  # barren
    'aec3d4'   # water
]

# Display the input and the classification with geemap in a notebook.
m = geemap.Map()
m.center_object(roi, 10)
m.add_layer(
    input_image.clip(roi),
    {'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 0, 'max': 0.25},
    'landsat',
)
m.add_layer(
    classified.clip(roi),
    {'palette': igbp_palette, 'min': 1, 'max': 17},
    'classification',
)
m

בדוגמה הזו נעשה שימוש בסיווג של יער אקראי (Breiman 2001) עם 10 עצים כדי להקטין את נתוני MODIS לרזולוציה של Landsat. השיטה sample() יוצרת שתי דגימות אקראיות מנתוני MODIS: אחת לאימון ואחת לאימות. הדגימה משמשת לאימון המסווג. אפשר לקבל דיוק של החלפה מחדש בנתוני האימון מ-classifier.confusionMatrix(). כדי לקבל דיוק באימות, צריך לסווג את נתוני האימות. הפעולה הזו מוסיפה מאפיין classification לאימות FeatureCollection. קוראים ל-errorMatrix() ב-FeatureCollection המסווג כדי לקבל מטריצת בלבול שמייצגת את דיוק האימות (הצפוי).

בודקים את הפלט כדי לוודא שהדיוק הכולל שחושב מנתוני האימון גבוה בהרבה מנתוני האימות. הדיוק שמוערך מנתוני האימון הוא הערכת יתר, כי היער האקראי "מותאם" לנתוני האימון. רמת הדיוק הצפויה בנתונים לא ידועים נמוכה יותר, כפי שמצוין בהערכה מנתוני האימות.

אפשר גם לקחת דגימה אחת ולחלק אותה באמצעות השיטה randomColumn() באוספי מאפיינים. בהמשך לדוגמה הקודמת:

Code Editor (JavaScript)

var sample = input.addBands(modis).sample({
  region: roi,
  numPixels: 5000,
  seed: 0
});

// The randomColumn() method will add a column of uniform random
// numbers in a column named 'random' by default.
sample = sample.randomColumn();

var split = 0.7;  // Roughly 70% training, 30% testing.
var training = sample.filter(ee.Filter.lt('random', split));
var validation = sample.filter(ee.Filter.gte('random', split));

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

sample = input_image.addBands(modis).sample(region=roi, numPixels=5000, seed=0)

# The randomColumn() method will add a column of uniform random
# numbers in a column named 'random' by default.
sample = sample.randomColumn()

split = 0.7  # Roughly 70% training, 30% testing.
training = sample.filter(ee.Filter.lt('random', split))
validation = sample.filter(ee.Filter.gte('random', split))

כדאי גם לוודא שאין קשר בין דוגמיות האימון לדוגמיות ההערכה. יכול להיות שהסיבה לכך היא מתאם מרחבי של התופעה שנחזית. אחת הדרכים להחריג דגימות שעשויות להיות קשורות זו לזו היא להסיר דגימות שנמצאות במרחק מסוים מדגימות אחרות. אפשר לעשות את זה באמצעות צירוף מרחבי:

Code Editor (JavaScript)

// Sample the input imagery to get a FeatureCollection of training data.
var sample = input.addBands(modis).sample({
  region: roi,
  numPixels: 5000,
  seed: 0,
  geometries: true,
  tileScale: 16
});

// The randomColumn() method will add a column of uniform random
// numbers in a column named 'random' by default.
sample = sample.randomColumn();

var split = 0.7;  // Roughly 70% training, 30% testing.
var training = sample.filter(ee.Filter.lt('random', split));
print('Training size:', training.size());
var validation = sample.filter(ee.Filter.gte('random', split));

// Spatial join.
var distFilter = ee.Filter.withinDistance({
  distance: 1000,
  leftField: '.geo',
  rightField: '.geo',
  maxError: 10
});

var join = ee.Join.inverted();

// Apply the join.
training = join.apply(training, validation, distFilter);
print('Training size after spatial filtering:', training.size());

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

# Sample the input imagery to get a FeatureCollection of training data.
sample = input_image.addBands(modis).sample(
    region=roi, numPixels=5000, seed=0, geometries=True, tileScale=16
)

# The randomColumn() method will add a column of uniform random
# numbers in a column named 'random' by default.
sample = sample.randomColumn()

split = 0.7  # Roughly 70% training, 30% testing.
training = sample.filter(ee.Filter.lt('random', split))
display('Training size:', training.size())
validation = sample.filter(ee.Filter.gte('random', split))

# Spatial join.
dist_filter = ee.Filter.withinDistance(
    distance=1000, leftField='.geo', rightField='.geo', maxError=10
)

join = ee.Join.inverted()

# Apply the join.
training = join.apply(training, validation, dist_filter)
display('Training size after spatial filtering:', training.size())

בקטע הקוד, שימו לב שהערך של geometries מוגדר כ-true ב-sample(). כך אפשר לשמור את המידע המרחבי של נקודות הדגימה שנדרשות לצירוף מרחבי. שימו לב גם שהערך של tileScale מוגדר ל-16. כך אפשר להימנע מהשגיאה "חריגה ממגבלת הזיכרון של המשתמש".

שמירת מסווגים

יכול להיות שלא ניתן יהיה לאמן מסווג על כמות גדולה של נתוני קלט באופן אינטראקטיבי, כי הקלט גדול מדי (יותר מ-99MB) או כי האימון נמשך יותר מדי זמן (5 דקות). משתמשים ב-Export.classifier.toAsset כדי להריץ את אימון המסווג כמשימת אצווה, שבה הוא יכול לפעול למשך זמן ארוך יותר עם יותר זיכרון. אפשר לייצא ולטעון מחדש מסווגים שדורשים אימון יקר כדי להימנע מהצורך לאמן אותם מחדש.

Code Editor (JavaScript)

// Using the random forest classifier defined earlier, export the random
// forest classifier as an Earth Engine asset.
var classifierAssetId = 'projects/<PROJECT-ID>/assets/upscaled_MCD12Q1_random_forest';
Export.classifier.toAsset(
  classifier,
  'Saved-random-forest-IGBP-classification',
  classifierAssetId
);

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

# Using the random forest classifier defined earlier, export the random
# forest classifier as an Earth Engine asset.
classifier_asset_id = (
    'projects/<PROJECT-ID>/assets/upscaled_MCD12Q1_random_forest'
)
task = ee.batch.Export.classifier.toAsset(
    classifier, 'Saved-random-forest-IGBP-classification', classifier_asset_id
)
task.start()

כדי לטעון את האלגוריתם המסווג השמור, משתמשים באלגוריתם ee.Classifier.load(), מציינים את מזהה האלגוריתם המסווג שיוצא ומשתמשים בו בדיוק כמו בכל אלגוריתם מסווג מאומן אחר.

Code Editor (JavaScript)

// Once the classifier export finishes, we can load our saved classifier.
var savedClassifier = ee.Classifier.load(classifierAssetId);
// We can perform classification just as before with the saved classifier now.
var classified = input.classify(savedClassifier);
Map.addLayer(classified.clip(roi),
             {palette: igbpPalette, min: 1, max: 17},
             'classification');

הגדרה של Python

בדף סביבת Python מפורט מידע על API בשפת Python ועל השימוש ב-geemap לפיתוח אינטראקטיבי.

import ee
import geemap.core as geemap

Colab (Python)

# Once the classifier export finishes, we can load our saved classifier.
saved_classifier = ee.Classifier.load(classifier_asset_id)
# We can perform classification just as before with the saved classifier now.
classified = input_image.classify(saved_classifier)

m = geemap.Map()
m.center_object(roi, 10)
m.add_layer(
    classified.clip(roi),
    {'palette': igbp_palette, 'min': 1, 'max': 17},
    'classification',
)
m