教師あり分類

Classifier パッケージは、Earth Engine で実行される従来の ML アルゴリズムによる教師あり分類を処理します。これらの分類器には、CART、RandomForest、NaiveBayes、SVM が含まれます。分類の一般的なワークフローは次のとおりです。

  1. トレーニング データを収集する。既知のクラスラベルを格納するプロパティと、予測変数の数値を格納するプロパティを持つフィーチャを組み立てます。
  2. 分類器をインスタンス化します。必要に応じてパラメータを設定します。
  3. トレーニング データを使用して分類器をトレーニングします。
  4. 画像または特徴コレクションを分類します。
  5. 独立した検証データを使用して分類エラーを推定する。

トレーニング データは、クラスラベルを格納するプロパティと、予測変数を格納するプロパティを持つ FeatureCollection です。クラスラベルは、0 から始まる連続した整数にする必要があります。必要に応じて、remap() を使用してクラス値を連続した整数に変換します。予測変数は数値にする必要があります。

トレーニング データや検証データは、さまざまなソースから取得できます。Earth Engine でトレーニング データをインタラクティブに収集するには、ジオメトリ描画ツールを使用します(コードエディタ ページのジオメトリ ツール セクションを参照)。または、Earth Engine テーブル アセットから事前定義されたトレーニング データをインポートすることもできます(詳細については、テーブルデータのインポート ページをご覧ください)。ee.Classifier のコンストラクタのいずれかから分類器を取得します。classifier.train() を使用して分類器をトレーニングします。classify() を使用して Image または FeatureCollection を分類します。次の例では、分類回帰ツリー(CART)分類器(Breiman et al. 1984)を使用して、次の 3 つの単純なクラスを予測します。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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() を使用して、分類器スキーマが画像と一致することを確認します。

トレーニング データが均一なリージョンを表すポリゴンの場合、各ポリゴンのすべてのピクセルがトレーニング ポイントになります。次の例に示すように、ポリゴンを使用してトレーニングできます。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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 は、一連のカスタム パラメータで指定されています。予測問題の物理的な性質に関する事前情報がない場合、最適なパラメータは不明です。SVM のパラメータを選択するための大まかなガイドについては、Hsu et al.(2003)をご覧ください。

分類器の出力モード

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 分類器を、デフォルトの分類ラベルではなく確率を出力するように構成できます。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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 参照画像からトレーニング データと検証データを生成し、トレーニングと検証の精度を表す混同行列を比較します。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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

この例では、10 本のツリーを持つランダム フォレスト(Breiman 2001)分類器を使用して、MODIS データを Landsat の解像度にダウンスケールします。sample() メソッドは、MODIS データから 2 つのランダム サンプル(トレーニング用と検証用)を生成します。トレーニング サンプルは、分類器のトレーニングに使用されます。 トレーニング データの再代入精度は classifier.confusionMatrix() から取得できます。検証の精度を取得するには、検証データを分類します。これにより、classification プロパティが検証 FeatureCollection に追加されます。分類された FeatureCollection で errorMatrix() を呼び出して、検証(期待される)精度を表す混同行列を取得します。

出力を調べて、トレーニング データから推定された全体的な精度が検証データよりもはるかに高いことを確認します。トレーニング データから推定された精度は、ランダム フォレストがトレーニング データに「適合」しているため、過大評価になります。検証データからの推定値が示すように、未知のデータに対する予想精度は低くなります。

また、1 つのサンプルを取得し、フィーチャ コレクションの randomColumn() メソッドを使用して分割することもできます。前の例の続き:

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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))

また、トレーニング サンプルが評価サンプルと相関していないことを確認することも必要です。これは、予測対象の現象の空間的自己相関が原因である可能性があります。 このように相関関係がある可能性のあるサンプルを除外する方法の 1 つは、他のサンプルから一定の距離内にあるサンプルを削除することです。これは、空間結合を使用して実現できます。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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())

前のスニペットでは、sample() で geometries が true に設定されています。これは、空間結合に必要なサンプルポイントの空間情報を保持するためです。また、tileScale が 16 に設定されていることに注意してください。これは、「ユーザーメモリの上限を超えました」というエラーを回避するためです。

分類器の保存

入力が大きすぎる(99 MB 超)か、トレーニングに時間がかかりすぎる(5 分)ため、大量の入力データで分類器をトレーニングすることは、インタラクティブにできない場合があります。Export.classifier.toAsset を使用して、分類器のトレーニングをバッチジョブとして実行します。これにより、より多くのメモリを使用して、より長い時間実行できます。トレーニングに費用がかかる分類器をエクスポートして再読み込みすることで、再トレーニングの必要性を回避できます。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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() を使用し、エクスポートした分類器 ID を指定して、他のトレーニング済み分類器と同様に使用します。

コードエディタ(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 とインタラクティブな開発での geemap の使用については、 Python 環境のページをご覧ください。

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