You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Google Earth Engine中实现k折交叉验证及精度评估

Google Earth Engine中土地覆盖分类的k折交叉验证实现

实现要点

  • 使用固定随机种子确保每次运行的训练/测试拆分完全一致
  • 将样本划分为k个互斥折叠,循环用k-1个折叠训练模型,剩余1个折叠测试
  • 收集每折的精度指标,最终计算所有折叠的平均精度

修改后的完整代码

var roi = ee.Geometry.Polygon(
    [[[30.68, -29.54],
      [30.72, -29.54],
      [30.72, -29.41],
      [30.68, -29.41],
      [30.68, -29.54]]]);

var period_of_interest = ee.Filter.date('2022-01-01', '2022-02-28');

/**
 * Function to mask clouds using the Sentinel-2 QA band
 * @param {ee.Image} image Sentinel-2 image
 * @return {ee.Image} cloud masked Sentinel-2 image
 */
function maskS2clouds(image) {
  var qa = image.select('QA60');

  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;

  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));

  return image.updateMask(mask).divide(10000);
}

//Build the Sentinel 2 collection, filtered by date, bounds and percentage of cloud cover 
var imageCollection = ee.ImageCollection('COPERNICUS/S2_SR')
                  .filter(period_of_interest)
                  .filterBounds(roi)
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',10))
                  .map(function(image){return image.clip(roi)})
                  .map(maskS2clouds)
//1 NDVI (Normalized Difference Vegetation Index)
var imageCollection = imageCollection.map(function(image) {   
    var NDVI = image.expression(
        "(NIR - RED) / (NIR + RED)",
        {
          RED: image.select("B4"),    //  RED
          NIR: image.select("B8"),    // NIR
}).rename('NDVI')
return image.addBands(NDVI)
})

//2 gNDVI (Green Normalized Difference Vegetation Index)
var imageCollection = imageCollection.map(function(image) { 
var gNDVI = image.expression(
        "(NIR - Green)/(NIR + Green)",
        { NIR: image.select("B8"),   
          Green: image.select("B3"),
}).rename('gNDVI')
return image.addBands(gNDVI)
})
          
//3 NDVIre (Normalized Difference Vegetation Index Red-edge)
var imageCollection = imageCollection.map(function(image) {
var NDVIre = image.expression(
        "(NIR - Rededge1) / (NIR + Rededge1)",
        { NIR: image.select("B8"),   
          Rededge1: image.select("B5"),
}).rename('NDVIre')
return image.addBands(NDVIre)
}); 
          
//4 EVI (Enhanced Vegetation Index)
var imageCollection = imageCollection.map(function(image) {
  var EVI = image.expression(
    '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
      'NIR': image.select('B8'),
      'RED': image.select('B4'),
      'BLUE': image.select('B2')
}).rename('EVI')
return image.addBands(EVI)
})

//5 SAVI (Soil Adjusted Vegetation Index)
var imageCollection = imageCollection.map(function(image) {
var SAVI = image.expression(
        "((NIRnarrow - RED) / (NIRnarrow + RED + 0.5) * 1.5)",
        {
          NIRnarrow: image.select("B8A"),    
          RED: image.select("B4")    
}).rename('SAVI')
return image.addBands(SAVI)
}); 
          
//6 SR-BlueRededge1 (Simple Blue and Red-edge 1 Ratio)
var imageCollection = imageCollection.map(function(image) {
var SRBlueRededge1 = image.expression(
        "(BLUE / REDedge1)",
        {
          BLUE: image.select("B2"),    
          REDedge1: image.select("B5")    
}).rename('SRBlueRededge1')
return image.addBands(SRBlueRededge1)
}); 

//7 SR-NIRnarrowRededge1 (Simple NIR and Red-edge 1 Ratio)
var imageCollection = imageCollection.map(function(image) {
var SRNIRnarrowRededge1 = image.expression(
        "(NIRnarrow / REDedge1)",
        {
          NIRnarrow: image.select("B8A"),    
          REDedge1: image.select("B5")    
}).rename('SRNIRnarrowRededge1')
return image.addBands(SRNIRnarrowRededge1)
}); 

//8 Pigment Specific Simple Ratio (chlorophyll index)
var imageCollection = imageCollection.map(function(image) {
var PSSRa = image.expression(
        "(NIR / RED)",
        { NIR: image.select("B8"),    
          RED: image.select("B4")    
}).rename('PSSRa')
return image.addBands(PSSRa)
}); 
        
//9 Chlogreen (Chlorophyll Green Index)
var imageCollection = imageCollection.map(function(image) {
var GCI = image.expression(
        "((NIR/Green))-1",
        {
          NIR: image.select("B8"),    
          Green: image.select("B3"),    
}).rename('GCI')
return image.addBands(GCI)
});
        
//10 BAI
var imageCollection = imageCollection.map(function(image) {
var BAI = image.expression(
        "(Blue - NIR)/(Blue + NIR)",
        { Blue: image.select("B2"),   
          NIR: image.select("B8"),    
}).rename('BAI')
return image.addBands(BAI)
});

//11 Lcaroc (Leaf Carotenoid Content)
var imageCollection = imageCollection.map(function(image) {
var Lcaroc = image.expression(
        "(Rededge3) / (Blue - Rededge1)",
        { Rededge3: image.select("B7"),    
          Blue: image.select("B2"),    
          Rededge1: image.select("B5"),    
          }).rename('Lcaroc')
return image.addBands(Lcaroc)
});

//12 Lchloc (Leaf Chlorophyll Content)
var imageCollection = imageCollection.map(function(image) {
var Lchloc = image.expression(
        "(Rededge3) / (Rededge1)",
        { Rededge3: image.select("B7"),    
          Rededge1: image.select("B5"),    
          }).rename('Lchloc')
return image.addBands(Lchloc)
});

//13 LAnthoC (Leaf Anthocynanid Content)
var imageCollection = imageCollection.map(function(image) {
var Lanthoc = image.expression(
        "(Rededge3) / (Green + Rededge1)",
        { Rededge3: image.select("B7"),
          Green: image.select("B3"),
          Rededge1: image.select("B5"),    
          }).rename('Lanthoc')
return image.addBands(Lanthoc)
});

//14 Mcari (Modified Chlorophyll Absorption in Reflectance Index)
var imageCollection = imageCollection.map(function(image) {
var Mcari = image.expression(
        "((Rededge1-Red)-0.2*(Rededge1-Green))*(Rededge1/Red)",
        { Red: image.select("B4"),
          Green: image.select("B3"),
          Rededge1: image.select("B5"),    
          }).rename('Mcari')
return image.addBands(Mcari)
});

//15 PSRI (Plant Senescence Reflectance Index)
var imageCollection = imageCollection.map(function(image) {
var PSRI = image.expression(
        "(Red-Green)/Rededge2",
        { Red: image.select("B4"),
          Green: image.select("B3"),
          Rededge2: image.select("B6"),    
          }).rename('PSRI')
return image.addBands(PSRI)
});

//16 PPR (Plant Pigment Ratio)
var imageCollection = imageCollection.map(function(image) {
var PPR = image.expression(
        "(Green-Blue)/(Green+Blue)",
        { Green: image.select("B3"),
          Blue: image.select("B2"),    
          }).rename('PPR')
return image.addBands(PPR)
});

//17 PVR (Photosyntetic Vigour Ratio)
var imageCollection = imageCollection.map(function(image) {
var PVR = image.expression(
        "(Green-Red)/(Green+Red)",
        { Green: image.select("B3"),
          Red: image.select("B4"),    
          }).rename('PVR')
return image.addBands(PVR)
});

var image = imageCollection.median()
print("Final_image", image);

// Create training data
var LULC = ee.FeatureCollection('users/shaedengokool/points')
Map.addLayer(LULC.style({color: 'black', fillColor: '00000000'}), false)
print (LULC)

var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B11', 'B12', 'NDVI',
            'gNDVI','NDVIre', 'EVI', 'SAVI', 'SRBlueRededge1', "SRNIRnarrowRededge1", 
            'PSSRa', 'GCI', 'BAI', 'Lcaroc', 'Lchloc', 'Lanthoc', 'Mcari', 'PSRI', 'PPR', 'PVR']
var training_data = image.select(bands).sampleRegions({
collection: LULC, 
  properties: ['Id'], 
  geometries: true,
  scale: 10.00,
  tileScale: 16, 
});
print(training_data, "training_data")

// -------------------------- k折交叉验证核心代码 --------------------------
var k = 5; // 设置折叠数,这里用5折
var seed = 1; // 固定随机种子,保证每次拆分一致

// 给每个样本分配折叠编号
var withFold = training_data.randomColumn('random', seed)
  .map(function(feature) {
    // 将0-1的随机数映射到0-(k-1)的折叠编号
    var fold = ee.Number(feature.get('random')).multiply(k).floor();
    return feature.set('fold', fold);
  });

// 生成折叠索引列表
var folds = ee.List.sequence(0, k-1);

// 定义每折的训练与评估逻辑
var kFoldResults = folds.map(function(foldNum) {
  foldNum = ee.Number(foldNum);
  
  // 拆分训练集(排除当前折叠)和测试集(当前折叠)
  var trainingSet = withFold.filter(ee.Filter.neq('fold', foldNum));
  var testSet = withFold.filter(ee.Filter.eq('fold', foldNum));
  
  // 训练梯度提升树分类器
  var classifier = ee.Classifier.smileGradientTreeBoost(300).train({
    features: trainingSet,
    classProperty: 'Id',
    inputProperties: bands
  });
  
  // 对测试集进行分类并计算混淆矩阵
  var validated = testSet.classify(classifier);
  var confMatrix = validated.errorMatrix('Id', 'classification');
  
  // 返回当前折叠的所有精度指标
  return ee.Dictionary({
    'fold': foldNum,
    'confusionMatrix': confMatrix,
    'overallAccuracy': confMatrix.accuracy(),
    'kappa': confMatrix.kappa(),
    'producersAccuracy': confMatrix.producersAccuracy(),
    'consumersAccuracy': confMatrix.consumersAccuracy()
  });
});

// 提取所有折叠的精度指标并计算平均值
var accuracyList = ee.List(kFoldResults);
var oaList = accuracyList.map(function(item) {
  return ee.Dictionary(item).get('overallAccuracy');
});
var kappaList = accuracyList.map(function(item) {
  return ee.Dictionary(item).get('kappa');
});

var meanOA = ee.Number(oaList.reduce(ee.Reducer.mean()));
var meanKappa = ee.Number(kappaList.reduce(ee.Reducer.mean()));

// 打印结果
print('各折叠详细精度结果', kFoldResults);
print('平均总体精度', meanOA);
print('平均Kappa系数', meanKappa);

// 可选:用全部样本训练最终分类器并生成分类图
var finalClassifier = ee.Classifier.smileGradientTreeBoost(300).train({
  features: training_data,
  classProperty: 'Id',
  inputProperties: bands
});
var classified = image.select(bands).classify(finalClassifier);
Map.addLayer(classified, {min: 1, max: 5, palette: ['#FF0000','#00FF00','#0000FF','#FFFF00','#FF00FF']}, '分类结果');

关键部分说明

  1. 固定随机种子
    在randomColumn方法中传入固定的seed参数(这里设为1),确保每次运行时样本的随机数生成完全一致,从而保证折叠划分的可重复性。

  2. 折叠划分逻辑
    通过将0-1的随机数乘以k后取整,把样本均匀分配到k个折叠中,每个折叠的样本量大致相等。

  3. 循环训练与评估
    利用ee.List.map遍历每个折叠,每次用k-1个折叠的样本训练模型,剩余1个折叠作为测试集,计算该折的混淆矩阵和精度指标。

  4. 平均精度计算
    提取所有折叠的总体精度和Kappa系数,用ee.Reducer.mean()计算平均值,得到模型的综合精度评估结果。

内容的提问来源于stack exchange,提问作者Shaeden Gokool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 19:12:49