当前位置:   article > 正文

GEE东拼西凑之随机森林分类_gee随机森林

gee随机森林

这里记录一下使用landsat5做随机森林分类的代码,理一下思路。很多内容都是到处找教程东拼西凑的,十分感谢各位大佬。

导入研究区、制作标签

首先加载研究区边界,查看需要分类时间的原影像。在影像上添加标签(目视解译)。

点击左边这个像小气球似的地方,修改名称,选择feature,添加properties。我是添加了两个一个是label,是分类名,另一个是lc,也就是landcover,用数字做区分。

 

 

制作完成之后就是这样的,然后需要将这些feature集合为collection。这里我去掉了bareland分类。

var regions = new ee.FeatureCollection([sand,water,crop,wetland,road_canal,construction]);

 值得注意的是,这些标签可以在其他文件中复用。点击imports部分右边蓝色本样子的图标,复制其中的代码到新的file中,会显示convert,转换一下之后就和上面界面一样了。

  1. var regions = new ee.FeatureCollection([sand,water,crop,wetland,road_canal,construction]);
  2. var table = ee.FeatureCollection("projects/ee-lzying1999/assets/Boundary-wgs");
  3. Map.centerObject(table, 9);
  4. Map.addLayer(ee.Image().paint(table, 0, 2), {}, 'roi');
  5. var date = ee.DateRange('2000-05-01','2000-10-01')

制作landsat影像集——尺度转换、添加光谱指数 

 这里是做一个预处理,主要是考虑到GEE中landsat影像集的缩放。以及后续分类要用到的光谱指数,在这里都处理好。在bands那里可以选择不同的波段以确定分类用到的特征变量。不过要注意的是,波段数太多可能超过GEE平台限制(80MiB),所以建议找最合适的变量。

  1. //product:LANDSAT/LT05/C02/T1_L2
  2. function input_landsat5L2(region,date){
  3. //缩放
  4. function applyScaleFactors(image) {
  5.   var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  6.   var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
  7.   return image.addBands(opticalBands, null, true)
  8.               .addBands(thermalBands, null, true);
  9. }
  10. //NDVI
  11. function NDVI(image) {
  12. return image.addBands(
  13. image.normalizedDifference(["SR_B4", "SR_B3"])
  14. .rename("NDVI"));
  15. }
  16. //EVI
  17. var EVI = function(image) {
  18. var evi = image.expression(
  19. '2.5 * float(nir - red)/ (nir + 6*red -7.5*blue +1 )',
  20. {
  21. 'nir': image.select('SR_B4'),
  22. 'red': image.select('SR_B3'),
  23. 'blue':image.select('SR_B1')
  24. }).rename('EVI');
  25. return image.addBands(evi);
  26. };
  27. //NDWI
  28. function NDWI(image) {
  29. return image.addBands(
  30. image.normalizedDifference(["SR_B2", "SR_B4"])
  31. .rename("NDWI"));
  32. }
  33. //MNDWI
  34. function MNDWI(image) {
  35. return image.addBands(
  36. image.normalizedDifference(["SR_B2", "SR_B5"])
  37. .rename("MNDWI"));
  38. }
  39. //NDBI
  40. function NDBI(image) {
  41. return image.addBands(
  42. image.normalizedDifference(["SR_B5", "SR_B4"])
  43. .rename("NDBI"));
  44. }
  45. //SI
  46. var SI = function(image) {
  47. var si = image.expression(
  48. 'float(swir + red-nir-blue)/ (swir +red +blue +nir )',
  49. {
  50. 'swir':image.select('SR_B5'),
  51. 'nir': image.select('SR_B4'),
  52. 'red': image.select('SR_B3'),
  53. 'blue':image.select('SR_B1')
  54. }).rename('SI');
  55. return image.addBands(si);
  56. };
  57. //SAVI
  58. var SAVI = function(image) {
  59. var savi = image.expression(
  60. '1.5*float(nir-red)/ (red +nir+0.5 )',
  61. {
  62. 'nir': image.select('SR_B4'),
  63. 'red': image.select('SR_B3'),
  64. }).rename('SAVI');
  65. return image.addBands(savi);
  66. };
  67. //DEM
  68. function DEM(image){
  69. var strm=ee.Image("USGS/SRTMGL1_003");
  70. var dem=ee.Algorithms.Terrain(strm);
  71. var elevation=dem.select('elevation');
  72. var slope=dem.select('slope');
  73. return image.addBands(elevation.rename("ELEVATION")
  74. ).addBands(slope.rename("SLOPE"))
  75. };
  76. //remove cloud by select bitwise(在网上找的去云方法)
  77. function bitwiseExtract(value, fromBit, toBit) {
  78. if (toBit === undefined) toBit = fromBit;
  79. var maskSize = 1 + toBit - fromBit; //位数
  80. var mask = ee.Number(1 << maskSize).subtract(1);
  81. return value.rightShift(fromBit).bitwiseAnd(mask);
  82. }
  83. function cloudfree_landsat(image){
  84. var qa = image.select('QA_PIXEL')
  85. var cloudState = bitwiseExtract(qa, 3) //5
  86. var cloudShadowState = bitwiseExtract(qa, 4) //3
  87. var mask = cloudState.eq(0) // Clear
  88. .and(cloudShadowState.eq(0)) // No cloud shadow
  89. return image.updateMask(mask)
  90. }
  91. //加载landsat影像
  92. var collection=
  93. ee.ImageCollection("LANDSAT/LT05/C02/T1_L2").filterDate(date).filterBounds(region);
  94. var preinput = collection.filterMetadata('CLOUD_COVER','less_than',3.0).sort('CLOUD_COVER', true)
  95. .map(cloudfree_landsat).map(applyScaleFactors)
  96. .map(NDVI)
  97. .map(NDWI)
  98. .map(NDBI)
  99. .map(MNDWI)
  100. .map(EVI).map(DEM).map(SI).map(SAVI);
  101. //选择不同的bands作为特征变量,可以多尝试哪个效果更好
  102. var bands = ["SR_B1", "SR_B2", "SR_B3","SR_B5", "SR_B7",
  103. "NDBI", "NDVI" ,'MNDWI','NDWI',"SAVI",'EVI','ELEVATION'//,'SI','SLOPE',];
  104. var input = preinput.select(bands);
  105. print(input);
  106. //看看原影像是什么样的(用于制作标签)
  107. Map.addLayer(preinput.mean().clip(region), {min:0, max:0.3, bands: ['SR_B3', 'SR_B2', 'SR_B1']} ,"rawscenecloud");
  108. return input
  109. }

划分数据集

这里我比较了mean、median、max、mosaic四种合成/镶嵌方式的效果,最后还是选择了mean。以mean作为分类的底图,也就是用各种波段、指数的平均值进行分类。然后7:3的比例划分数据集。

  1. //调用上面处理好的landsat数据集
  2. var input = input_landsat5L2(table,date)
  3. //按不同方式合成
  4. var mean = input.mean().clip(table)
  5. var median = input.median().clip(table)
  6. var max = input.max().clip(table)
  7. var mosaic = input.mosaic().clip(table)
  8. // 选取样本,把landcover属性赋予样本
  9. var training = mean.sampleRegions({
  10. collection: regions,
  11. properties: ['lc'],
  12. scale: 30
  13. });
  14. print(training,'training')
  15. //样本点随机排列
  16. var withRandom = training.randomColumn('random');
  17. //以7:3的比例划分训练集和测试集
  18. var split = 0.7;
  19. var trainingPartition = withRandom.filter(ee.Filter.lt('random', split));
  20. var testingPartition = withRandom.filter(ee.Filter.gte('random', split));

确定随机森林树的数目

这里再次感谢各路大佬。

  1. //选取随机森林树数目
  2. var numTrees = ee.List.sequence(5, 50, 5);
  3. var accuracies = numTrees.map(function(t)
  4. {
  5. var classifier1 = ee.Classifier.smileRandomForest(t)
  6. .train({
  7. features: trainingPartition,
  8. classProperty: 'lc',
  9. inputProperties: mean.bandNames()
  10. });
  11. return testingPartition
  12. .classify(classifier1)
  13. .errorMatrix('lc', 'classification')
  14. .accuracy();
  15. });
  16. print(ui.Chart.array.values({
  17. array: ee.Array(accuracies),
  18. axis: 0,
  19. xLabels: numTrees
  20. }));

然后就可以选择精度最高的了。

训练并分类

这里之前还弄出来笑话了,因为没仔细看大佬的代码,只分类了测试集,没有对整张图像分类,还到处搜为什么不出图。。

  1. //训练
  2. var classifier = ee.Classifier.smileRandomForest(20)
  3. .train({
  4. features: trainingPartition, //训练集
  5. classProperty: 'lc', //标签
  6. inputProperties: mean.bandNames() //波段名,设置了输入图像的波段
  7. });
  8. //将分类器应用于整张图
  9. var img_RF = mean.classify(classifier);
  10. print(img_RF,'img_RF')
  11. var imageVisParam = {min:1,max:6, palette:['yellow','blue','green','darkgreen','brown','grey']}/
  12. Map.addLayer(img_RF,imageVisParam,'Classified_RF');
  13. //用分类器对测试集进行分类
  14. var Classified_RF = testingPartition.classify(classifier);
  15. print(Classified_RF,'Classified_RF')

 精度分析

精度分析也是很全面了,论文中常见的系数都能计算。本质都是基于混淆矩阵计算的。

  1. //混淆矩阵
  2. var testAccuracy = Classified_RF.errorMatrix('lc', 'classification');
  3. //总准确度
  4. var accuracy = testAccuracy.accuracy();
  5. //用户精度(多分误差)
  6. var userAccuracy = testAccuracy.consumersAccuracy();
  7. //制图精度(漏分误差)
  8. var producersAccuracy = testAccuracy.producersAccuracy();
  9. //Kappa系数,不仅考虑混淆矩阵对角线上精准分类的数量,也考虑了各种漏分、误分情况
  10. var kappa = testAccuracy.kappa();
  11. print('Validation error matrix:', testAccuracy);
  12. print('Validation overall accuracy:', accuracy);
  13. print('User acc:', userAccuracy);
  14. print('Prod acc:', producersAccuracy);
  15. print('Kappa:', kappa);

特征重要性分析

  1. //几乎没有参数需要改
  2. var dict = classifier.explain();
  3. print('Explain:',dict);
  4. var variable_importance = ee.Feature(null, ee.Dictionary(dict).get('importance'));
  5. var chart_im =
  6. ui.Chart.feature.byProperty(variable_importance)
  7. .setChartType('ColumnChart')
  8. .setOptions({
  9. title: 'Random Forest Variable Importance',
  10. legend: {position: 'none'},
  11. hAxis: {title: 'Bands'},
  12. vAxis: {title: 'Importance'}
  13. });
  14. print(chart_im);

在应用的过程中,发现变量的重要性总是在变,不知道是不是正常的。。不过也总能找到一两个在任何尝试中重要性都比较低的变量,所以去掉了。

 

后记

发现CSDN上大佬真的太多了!虽然在尝试过程中闹了不少乌龙,但是最后总算能跑出来一个还挺不错的结果。我尝试了不同的合成方式、不同的特征变量、影像集不同时间段,期间还改了几次标签,感觉结果有点玄学。。标签真的太重要,精度很低的时候我发现好几个标签都打错了。。。更改之后有明显提升。但是对于长时间年份,每年都打几百上千的标签有点要命,所以打算把建筑、沙地、水体这种不会有明显变化的标签复用。还有就是GEE因为波段太多会停摆,在想如果在GEE上下载处理好的影像(mean)到本地,再用Python去跑随机森林代码效果会更好吗?苦于Python水平也很差,所以就先这样吧。。。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/239196
推荐阅读
相关标签
  

闽ICP备14008679号