python森林生物量(蓄积量)数据处理到随机森林估算全流程

python森林生物量(蓄积量)估算全流程

  • 一.哨兵2号获取/处理/提取数据
    • 1.1 影像处理与下载
      • 采用云概率影像去云
      • 采用6S模型对1C级产品进行大气校正
      • geemap下载数据到本地
      • NDVI
    • 1.2 各种参数计算(生物物理变量、植被指数等)
      • LAI:叶面积指数
      • FAPAR:吸收的光合有效辐射的分数
      • FVC:植被覆盖率
      • GEE计算植被指数
      • 采用gdal计算各类植被指数
    • 1.3 纹理特征参数提取
  • 二.哨兵1号获取/处理/提取数据
    • 2.1 纹理特征参数提取
  • 三、DEM数据
    • 3.1 数据下载
    • 3.2 数据处理
  • 四、样本生物量计算
  • 五、样本变量选取
  • 六、随机森林建模
    • 6.1导入库与变量准备
    • 6.2 选取参数
    • 6.3 误差分布直方图
    • 6.4 变量重要性可视化展示
    • 6.5 对精度进行验证
    • 6.6 预测生物量
  • 七、生物量制图
    • 7.1. 将得到的biomass.tif文件按掩膜提取
    • 7.2. 提取森林掩膜区域
  • 八. 需要注意的点

一.哨兵2号获取/处理/提取数据

1.1 影像处理与下载

这里采用哨兵12号影像估算森林生物量
在GEE上处理和下载2017年的S2L1C级产品,因为S2L2A级产品(经过大气校正)量少,没有2017年的可用产品。

这里需要对S2L1C产品进行大气较正,采用6S模型,运行这个库需要安装。
可以看这篇文章完成

#导入必要的库文件
import ee
from Py6S import *
import datetime
import math
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.getcwd()),'bin'))
from atmospheric import Atmospheric
ee.Initialize()
import geemap
wanzhou = geemap.geojson_to_ee("./input/wanzhou.json")
roi = wanzhou.geometry().bounds()
geom = wanzhou.geometry().bounds()

采用云概率影像去云

s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED")
s2_cloud = ee.ImageCollection("COPERNICUS/S2_CLOUD_PROBABILITY")
point = roidef rmCloudByProbability(image, thread):prob = image.select("probability")return image.updateMask(prob.lte(thread))def scaleImage(image):time_start = image.get("system:time_start")image = image.divide(10000)image = image.set("system:time_start", time_start)return imagedef getMergeImages(primary, secondary):join = ee.Join.inner()filter = ee.Filter.equals(leftField='system:index', rightField='system:index')joinCol = join.apply(primary, secondary, filter)joinCol = joinCol.map(lambda image: ee.Image(image.get("primary")).addBands(ee.Image(image.get("secondary"))))return ee.ImageCollection(joinCol)startDate = "2016-06-01"
endDate = "2016-10-31"
ee.Date(startDate)
ee.Date(endDate)
s2_raw = s2.filterDate(startDate, endDate).filterBounds(point)
s2Imgs1 = s2.filterDate(startDate, endDate).filterBounds(point).map(scaleImage)
s2Imgs2 = s2_cloud.filterDate(startDate, endDate).filterBounds(point)
s2Imgs = getMergeImages(s2Imgs1, s2Imgs2)
s2Imgs = s2Imgs.map(lambda image: rmCloudByProbability(image,40))
s2Img = s2Imgs.median()composite = s2Img.clip(point).toFloat()
rgbVis = {'min': 0.0,'max': 0.3,'bands': ['B4', 'B3', 'B2'],
}
styling = {'color': 'red','fillColor': '00000000'
}
#随后创建一个 Map 实例,将栅格和矢量添加到图层中。
Map = geemap.Map()
Map.addLayer(composite,rgbVis, "S2_2A_wanzhou")
Map.addLayer(wanzhou.style(**styling), {}, '万州边界')
Map.centerObject(wanzhou, 9)
Map
toa = composite

采用6S模型对1C级产品进行大气校正

date = ee.Date('2016-07-01')geom = ee.Geometry.Point(107.7632, 30.8239)
S2 = ee.Image(ee.ImageCollection('COPERNICUS/S2').filterBounds(geom).filterDate(date,date.advance(3,'month')).sort('system:time_start').first())
info = S2.getInfo()['properties']
scene_date = datetime.datetime.utcfromtimestamp(info['system:time_start']/1000)# i.e. Python uses seconds, EE uses milliseconds
solar_z = info['MEAN_SOLAR_ZENITH_ANGLE']
date = ee.Date('2016-07-01')h2o = Atmospheric.water(geom,date).getInfo()
o3 = Atmospheric.ozone(geom,date).getInfo()
aot = Atmospheric.aerosol(geom,date).getInfo()SRTM = ee.Image('CGIAR/SRTM90_V4')# Shuttle Radar Topography mission covers *most* of the Earth
alt = SRTM.reduceRegion(reducer = ee.Reducer.mean(),geometry = geom.centroid()).get('elevation').getInfo()
km = alt/1000 # i.e. Py6S uses units of kilometers# Instantiate
s = SixS()# Atmospheric constituents
s.atmos_profile = AtmosProfile.UserWaterAndOzone(h2o,o3)
s.aero_profile = AeroProfile.Continental
s.aot550 = aot# Earth-Sun-satellite geometry
s.geometry = Geometry.User()
s.geometry.view_z = 0               # always NADIR (I think..)
s.geometry.solar_z = solar_z        # solar zenith angle
s.geometry.month = scene_date.month # month and day used for Earth-Sun distance
s.geometry.day = scene_date.day     # month and day used for Earth-Sun distance
s.altitudes.set_sensor_satellite_level()
s.altitudes.set_target_custom_altitude(km)def spectralResponseFunction(bandname):"""Extract spectral response function for given band name"""bandSelect = {'B1':PredefinedWavelengths.S2A_MSI_01,'B2':PredefinedWavelengths.S2A_MSI_02,'B3':PredefinedWavelengths.S2A_MSI_03,'B4':PredefinedWavelengths.S2A_MSI_04,'B5':PredefinedWavelengths.S2A_MSI_05,'B6':PredefinedWavelengths.S2A_MSI_06,'B7':PredefinedWavelengths.S2A_MSI_07,'B8':PredefinedWavelengths.S2A_MSI_08,'B8A':PredefinedWavelengths.S2A_MSI_8A,'B9':PredefinedWavelengths.S2A_MSI_09,'B10':PredefinedWavelengths.S2A_MSI_10,'B11':PredefinedWavelengths.S2A_MSI_11,'B12':PredefinedWavelengths.S2A_MSI_12,}return Wavelength(bandSelect[bandname])def toa_to_rad(bandname):"""Converts top of atmosphere reflectance to at-sensor radiance"""# solar exoatmospheric spectral irradianceESUN = info['SOLAR_IRRADIANCE_'+bandname]solar_angle_correction = math.cos(math.radians(solar_z))# Earth-Sun distance (from day of year)doy = scene_date.timetuple().tm_ydayd = 1 - 0.01672 * math.cos(0.9856 * (doy-4))# http://physics.stackexchange.com/questions/177949/earth-sun-distance-on-a-given-day-of-the-year# conversion factormultiplier = ESUN*solar_angle_correction/(math.pi*d**2)# at-sensor radiancerad = toa.select(bandname).multiply(multiplier)return raddef surface_reflectance(bandname):"""Calculate surface reflectance from at-sensor radiance given waveband name"""# run 6S for this wavebands.wavelength = spectralResponseFunction(bandname)s.run()# extract 6S outputsEdir = s.outputs.direct_solar_irradiance             #direct solar irradianceEdif = s.outputs.diffuse_solar_irradiance            #diffuse solar irradianceLp   = s.outputs.atmospheric_intrinsic_radiance      #path radianceabsorb  = s.outputs.trans['global_gas'].upward       #absorption transmissivityscatter = s.outputs.trans['total_scattering'].upward #scattering transmissivitytau2 = absorb*scatter                                #total transmissivity# radiance to surface reflectancerad = toa_to_rad(bandname)ref = rad.subtract(Lp).multiply(math.pi).divide(tau2*(Edir+Edif))return ref# # surface reflectance rgb
# b = surface_reflectance('B2')
# g = surface_reflectance('B3')
# r = surface_reflectance('B4')
# ref = r.addBands(g).addBands(b)# all wavebands
output = S2.select('QA60')
for band in ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12']:
#     print(band)output = output.addBands(surface_reflectance(band))
#随后创建一个 Map 实例,将栅格和矢量添加到图层中。
Map = geemap.Map()
Map.addLayer(output, rgbVis, '万州')
Map.addLayer(wanzhou.style(**styling), {}, '万州边界')
Map.centerObject(wanzhou, 9)
Map

geemap下载数据到本地

这里需要安装geemap库,具体可以参考这篇文章

#定义下载函数
def download(image):band_name = image.bandNames().getInfo()band_name_str = str(band_name).replace('[', '').replace(']', '').replace("'", '')work_dir = os.path.join(os.path.expanduser("E:\jupyter\geeDownloads"), 'tif')if not os.path.exists(work_dir):os.makedirs(work_dir)out_tif = os.path.join(work_dir, str(band_name_str)+"_S2_2016_wanzhou.tif")geemap.download_ee_image(image=image,filename=out_tif,region=wanzhou.geometry(),crs="EPSG:4326",scale=10,)return image
#下载原始数据download(output)

NDVI

# 选择 Sentinel-2 的红波段(B4)和近红外波段(B8)
red = output.select('B4')
nir = output.select('B8')# 计算归一化植被指数(NDVI)
ndvi = nir.subtract(red).divide(nir.add(red)).rename('ndvi')# 设置可视化参数
vis_params = {'min': -1,'max': 1,'palette': ['blue', 'white', 'green']
}
ndvi = ndvi.clip(wanzhou)
# 在地图上添加 NDVI 图层
Map.addLayer(ndvi, vis_params, "NDVI_S2_2016")
Map
download(ndvi)

1.2 各种参数计算(生物物理变量、植被指数等)

LAI:叶面积指数

这几个参数都用用snap软件打开,但是从GEE上下载的数据是tif格式的,缺失了头文件,不能用SNAP处理,我也不知道有什么好的解决方法呜呜呜

参考链接

参考文献:Boegh E,Soegaard H,Broge N,et al.Airborne multispectral data for
quantifying leaf area index,nitrogen concentration,and photosynthetic
efficiency in agriculture[J].Remote Sensing of
Environment,2002,81(2):179-193.

公式:LAI=3.618*EVI-0.118

EVI = output.expression('2.5*((NIR - RED)/(NIR + 6*RED-7.5*BLUE+1))',{'NIR':output.select('B8'),'RED':output.select('B4'),'BLUE':output.select('B2')}
).float().rename('EVI')LAI = output.expression('3.618*EVI-0.118',{'EVI':EVI.select('EVI'),}
).rename('LAI')
LAI=LAI.clip(wanzhou)download(LAI)

FAPAR:吸收的光合有效辐射的分数

参考链接

LAI和FAPAR之间存在一定的数学关系,通常使用经验公式来描述它们之间的关系。其中最常用的公式是:

FAPAR = exp(-k * LAI)

其中,k是一个常数,通常取值在0.5左右。这个公式表明,FAPAR与LAI成指数反比关系,即LAI越高,FAPAR越低。

这个公式的基本原理是,LAI越高,表示单位面积内植物叶面积越大,可以吸收更多的光能,导致FAPAR值降低。而当赖

需要注意的是,这个公式是一种经验公式,适用于各种植被类型和环境条件。在实际应用中,还需要考虑到植被的结构、生长状态、光谱特征等因素,以获得更准确的LAI和FAPAR估算结果。

FAPAR = output.expression('exp(-0.51*LAI)',{'LAI':LAI.select('LAI')}
).float().rename('FAPAR')download(FAPAR)

FVC:植被覆盖率

参考链接1

参考链接2

FVC = (NDVI -NDVIsoil)/ ( NDVIveg - NDVIsoil)

在ndvi影像值统计结果中,最后一列表示对应NDVI值的累积概率分布。我们分别取累积概率为5%和90%的NDVI值作为NDVImin和NDVImax

#计算NDVImin和NDVImax
from osgeo import gdal
import numpy as npinputRaster = gdal.Open(r"E:\jupyter\geeDownloads\NDVI_2016_wanzhou.tif")  # 输入的遥感影像数据
# inputRaster = gdal.Open(r"E:\jupyter\geeDownloads\tif\NDVI.tif")  # 输入的遥感影像数据
ndviBand = inputRaster.GetRasterBand(1)
ndviValues = ndviBand.ReadAsArray()  # 将 NDVI 栅格数据转换为 numpy 数组# 统计 NDVI 值的分布
ndviHist, ndviBins = np.histogram(ndviValues, bins=1000, range=(-1, 1))
ndviCumHist = np.cumsum(ndviHist) / ndviValues.size# 找到累积概率值分别为 0.05 和 0.9 时对应的 NDVI 值
ndviBinSize = ndviBins[1] - ndviBins[0]
ndviSoilIndex = np.where(ndviCumHist <= 0.05)[0][-1]
ndviSoil = ndviBins[ndviSoilIndex] + ndviBinSize / 2
ndviVegIndex = np.where(ndviCumHist <= 0.9)[0][-1]
ndviVeg = ndviBins[ndviVegIndex] + ndviBinSize / 2# 输出统计结果
print("ndviSoil: {:.3f}".format(ndviSoil))
print("ndviVeg: {:.3f}".format(ndviVeg))

然后在ArcGis中栅格计算器中计算:
Con((“NDVI.tif” >= 0.503) & (“NDVI.tif” <= 0.999), ((“NDVI.tif” - 0.503) / (0.999 - 0.503)), 0)

GEE计算植被指数

这是可选项,如果你wifi质量好,可以这样下载,当然还是建议本地计算栅格

1.比值植被指数RVI =B8/B4

2.红外植被指数IPVI=B8/(B8+B4)

3.垂直植被指数PVI=SIN(45)*B8-COS(45)*B4

4.反红边叶绿素指数IRECI=(B8-B4)/(B8+B4)

5.土壤调节植被指数SAVI=((B8-B4)/(B8+B4+L))(1+L) L取0.5

6.大气阻抗植被指数ARVI=B8-(2*B4-B2)/B8+(2B4-B2)

7.特定色素简单比植被指数PSSRa=B7/B4

8.Meris陆地叶绿素指数MTCI=(B6-B5)/(B5-B4)

9.修正型叶绿素吸收比值指数MCARI=[B5-B4]-0.2*(B5-B3)]*(B5-B4)

10.REIP红边感染点指数REIP=700+40*[(B4+B7)/2-B5]/(B6-B5)

import numpy as np
# 选择需要的波段
b4= output.select('B4')# 红波段
b8= output.select('B8')#近红外
b2= output.select('B2')#蓝波段
b3= output.select('B3')#绿波段
b7 = output.select('B7')#红边3波段
b5= output.select('B5')#红边1波段
b6 = output.select('B6')#红边2波段# 比值植被指数RVI = B8/B4
rvi = b8.divide(b4).rename('rvi')
download(rvi)# 红外植被指数IPVI = B8/(B8+B4)
ipvi = b8.divide(b8.add(b4)).rename('ipvi')
download(ipvi)# 垂直植被指数PVI = SIN(45)*B8 - COS(45)*B4
pvi = b8.multiply(np.sin(45)).subtract(b4.multiply(np.cos(45))).rename('pvi')
download(pvi)# 反红边叶绿素指数IRECI=(B8-B4)/(B8+B4)
ireci = b8.subtract(b4).divide(b8.add(b4)).rename('ireci')
download(ireci)# 土壤调节植被指数SAVI=((NIR-R)/(NIR+R+L))(1+L)
L = 0.5  # 土壤校正因子
savi = b8.subtract(b4).divide(b8.add(b4).add(L)).multiply(1 + L).rename('savi')
download(savi)# 大气阻抗植被指数ARVI=[NIR - (2xRed-BLUE)] / [NIR + (2xRed-BLUE)]
arvi = b8.subtract(b4.multiply(2).subtract(b2)).divide(b8.add(b4.multiply(2).subtract(b2))).rename('arvi')
download(arvi)# 特定色素简单比植被指数PSSRa = B7/B4
pssra = b7.divide(b4).rename('pssra')
download(pssra)# Meris陆地叶绿素指数MTCI = (B6 - B5)/(B5 - B4 - 0.01)
mtci = b6.subtract(b5).divide(b5.subtract(b4).subtract(0.01)).rename('mtci')
download(mtci)# 修正型叶绿素吸收比值指数MCARI = (B5 - B4 - 0.2*(B5 - B3))*(B5-B4)
mcari = b5.subtract(b4).subtract((b5.subtract(b3)).multiply(0.2)).multiply(b5.subtract(b4)).rename('mcari')
download(mcari)# REIP红边感染点指数REIP = 700 + 40*((B4+B7)/2 - B5)/(B6 - B5)
reip = ee.Image(700).add(ee.Image(40).multiply(b4.add(b7).divide(2).subtract(b5).divide(b6.subtract(b5)))).rename('reip')
download(reip)

采用gdal计算各类植被指数

Sentinel-2 影像文件名 s.tif,然后使用以下命令将指数计算转换为 GDAL python本地计算

安装gdal库,安装gdal库建议采用本地安装,去下载whl文件,然后转到放置whl文件的目录下,pip install 即可
进入安装好gdal库的虚拟环境,然后将gdal_calc.py下载地址和s.tif文件放在同一个文件夹下。运行python gdal_calc.py文件

RVI:

python gdal_calc.py -A s.tif --A_band=4 -B s_wanzhou.tif --B_band=8 --outfile=rvi_wanzhou.tif --calc="(B/A)"

IPVI:

python gdal_calc.py -A s.tif --A_band=4 -B s_wanzhou.tif --B_band=8 --outfile=ipvi_wanzhou.tif --calc="(B/(A+B))"

PVI:

python gdal_calc.py -A s.tif --A_band=4 -B s.tif --B_band=8 --outfile=pvi.tif --calc="(sin(pi/4)*B)-(cos(pi/4)*A)"

IRECI:

python gdal_calc.py -A s.tif --A_band=4 -B s.tif --B_band=8 --outfile=ireci.tif --calc="((B-A)/(B+A))"

SAVI:

python gdal_calc.py -A s_wanzhou.tif --A_band=4 -B s_wanzhou.tif --B_band=8 --outfile=savi_wanzhou.tif --calc="((B-A)/(B+A+0.5))*(1+0.5)"

ARVI:

python gdal_calc.py -A s_wanzhou.tif -B s_wanzhou.tif -C s_wanzhou.tif --A_band=4 --B_band=8 --C_band=2 --outfile=arvi_wanzhou.tif --calc="((B-(2*A-C))/(B+(2*A-C)))"

PSSRa:

python gdal_calc.py -A s_wanzhou.tif --A_band=4 -B s_wanzhou.tif --B_band=7 --outfile=pssra_wanzhou.tif --calc="(B/A)"

MTCI:

python gdal_calc.py -A s_wanzhou.tif --A_band=4 -B s_wanzhou.tif --B_band=5 -C s_wanzhou.tif --C_band=6 --outfile=mtci_wanzhou.tif --calc="((B-C)/(C-A-0.01))"

MCARI:

python gdal_calc.py -A s_wanzhou.tif --A_band=4 -B s_wanzhou.tif --B_band=5 -C s_wanzhou.tif --C_band=3 --outfile=mcari_wanzhou.tif --calc="((B-A)-(0.2*(B-C)))*(B-A)"

REIP:

python gdal_calc.py -A s_wanzhou.tif --A_band=4 -B s_wanzhou.tif --B_band=5 -C s_wanzhou.tif --C_band=6 -D s_wanzhou.tif --D_band=7 --outfile=reip_wanzhou.tif --calc="(700)+(40*((B+D)/2-A)/(C-A))"

请注意,这里的 s.tif 文件名应该与你的实际文件名相匹配,而且在计算 SAVI 时,你需要预先定义 L 的值并将其替换为相应的值。

采用gdal_calc.py的命令计算一下哨兵二号的

NDVI78a (NIR2 – RE3)/ (NIR2 + RE3)

NDVI67 (RE3- RE2)/ (RE3+ RE2)

NDVI58a (NIR2- RE1)/ (NIR2 + RE1)

NDVI56 (RE2- RE1)/ (RE2+ RE1)

NDVI57 (RE3- RE1)/ (RE3+ RE1)

NDVI68a (NIR2 - RE2)/ (NIR2 + RE2)

NDVI48 (NIR - R)/ (NIR + R)
注:蓝波段(B)、绿波段 (G)、红波段 ®、近红外波段(NIR1)、窄近红外波段 (NIR2)、红边波段 1 (RE1)、
红边波段 2 (RE2)、红边波段 3 (RE3).

python gdal_calc.py -A sentinel2.tif --A_band=8 -B sentinel2.tif --B_band=7 --outfile=ndvi78a.tif --calc="(A-B)/(A+B)" --NoDataValue=0python gdal_calc.py -A sentinel2.tif --A_band=7 -B sentinel2.tif --B_band=6 --outfile=ndvi67.tif --calc="(A-B)/(A+B)" --NoDataValue=0python gdal_calc.py -A sentinel2.tif --A_band=8 -B sentinel2.tif --B_band=5 --outfile=ndvi58a.tif --calc="(A-B)/(A+B)" --NoDataValue=0python gdal_calc.py -A sentinel2.tif --A_band=6 -B sentinel2.tif --B_band=5 --outfile=ndvi56.tif --calc="(A-B)/(A+B)" --NoDataValue=0python gdal_calc.py -A sentinel2.tif --A_band=7 -B sentinel2.tif --B_band=5 --outfile=ndvi57.tif --calc="(A-B)/(A+B)" --NoDataValue=0python gdal_calc.py -A sentinel2.tif --A_band=8 -B sentinel2.tif --B_band=6 --outfile=ndvi68a.tif --calc="(A-B)/(A+B)" --NoDataValue=0python gdal_calc.py -A sentinel2.tif --A_band=8 -B sentinel2.tif --B_band=4 --outfile=ndvi48.tif --calc="(A-B)/(A+B)" --NoDataValue=0

1.3 纹理特征参数提取

采用envi软件
有研究表明,遥感数据的纹理信息能够增强原始影像亮度的空间信息辨识度,提升地表参数的反演精度。本研究采用灰度共生矩阵( gray level co-occurrence matrix,GLCM) 提取纹理特征信息,究纹理窗口大小设置为 3×3,获取8类 纹 理 特 征 值。
灰度共生矩阵提取纹理特征信息可参考
在这里插入图片描述
处理完后可将纹理信息提取出来,可通过APP store 中的Split to Multiple Single-Band Files 工具进行直接拆分
Sentinel-2中10个波段每个波段的纹理信息共80个

二.哨兵1号获取/处理/提取数据

哨兵1号数据在欧空局中下载,然后采用SNAP软件对其进行一系列处理
可参考链接
处理后记得把坐标系和投影转成和哨兵2号一样

2.1 纹理特征参数提取

同1.3
基于 VH 和VV 极化影像提取纹理特征信息,获 取 8X2=16 个 纹 理 特 征
在这里插入图片描述在这里插入图片描述

三、DEM数据

3.1 数据下载

可参考这篇文章进行数据下载

3.2 数据处理

一定要注意呀!
获取的数据是30m分辨率的,哨兵数据是10米分辨率,在arcGis中搜索resample 需要将DEM重采样到10米分辨率。
然后在ArcGis中搜索坡度和坡向这两个工具,分别计算这两变量。

四、样本生物量计算

代码如下,d代表胸径,h代表树高
查找优势树种对应的异速生长方程写上就行


import pandas as pd
# 读取 CSV 文件
df = pd.read_csv('E:\Sentinel12\yangben\yangben.csv', encoding='gbk')
# 定义优势树种类型及对应的
tree_types = {'柏木': lambda d, h: 0.12703 * (d ** 2 * h )** 0.79775,'刺槐': lambda d, h: ( 0.05527 * (d ** 2 * h )** 0.8576) + (  0.02425* (d ** 2 * h )** 0.7908) +( 0.0545 * (d ** 2 * h )** 0.4574),#http://www.xbhp.cn/news/11502.html'栎类': lambda d, h:0.16625 * ( d ** 2 * h ) ** 0.7821,'柳杉': lambda d, h:( 0.2716 * ( d ** 2 * h ) ** 0.7379 ) + ( 0.0326 * ( d ** 2 * h ) ** 0.8472 ) + ( 0.0250 * ( d ** 2 * h ) ** 1.1778 ) + ( 0.0379 * ( d ** 2 * h ) ** 0.7328 ),'马尾松': lambda d, h: 0.0973 * (d ** 2 * h )** 0.8285,'其他硬阔': lambda d, h:( 0.0125 * (d ** 2 * h )**1.05 ) + (  0.000933* (d ** 2 * h )**1.23 ) +( 0.000394 * (d ** 2 * h )** 1.20),'杉木': lambda d, h: ( 0.00849 * (d ** 2 * h) ** 1.107230) + ( 0.00175 * (d ** 2 * h )** 1.091916) + 0.00071 * d **3.88664 ,'湿地松': lambda d, h: 0.01016* (d ** 2 * h )**1.098,'香樟': lambda d, h:( 0.05560 * (d ** 2 * h )** 0.850193) + ( 0.00665 * (d ** 2 * h )** 1.051841) +( 0.05987 * (d ** 2 * h )** 0.574327)+( 0.01476 * (d ** 2 * h )** 0.808395) ,'油桐': lambda d, h: ( 0.086217 *d ** 2.00297)+ ( 0.072497 *d ** 2.011502)+( 0.035183 *d ** 1.63929),'杨树': lambda d, h: ( 0.03 * (d ** 2 * h )** 0.8734) + ( 0.0174 * (d ** 2 * h )** 0.8574) +( 0.4562 * (d ** 2 * h )** 0.3193)+( 0.0028 * (d ** 2 * h )**0.9675 ) ,
}# 遍历样本并计算地上生物量```python
for i, row in df.iterrows():tree_type = row['优势树']if tree_type in tree_types:sd = row['平均胸径']h = row['林分平均树高']biomass = tree_types[tree_type](d, h)df.at[i, '生物量'] = biomass# 将计算后的地上生物量写入 CSV 文件
df.to_csv('E:\Sentinel12\yangben\yangben_processed.csv', index=False)

五、样本变量选取

将样本导入arcgis,设置好投影信息,在ArcGis中找到多值提取至点工具。
参考这篇文章

六、随机森林建模

参考1
参考2
可以用SPSS进行相关性分析,可参考,选择相关性比较大的变量进行建模
随机森林代码如下:

6.1导入库与变量准备

记得安装sklearn包
命令行如下:

pip install scikit-learn

本文中设计到的所有python代码均在jupyter notebook中运行

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
from pyswarm import pso
import rasterio
# import pydot
import numpy as np
import pandas as pd
import scipy.stats as stats
from pprint import pprint
from sklearn import metrics
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV
from joblib import dump
# 读取Excel表格数据
data = pd.read_csv(r'E:\Sentinel12\yangben\建模\jianmo.csv' )
y = data.iloc[:, 0].values  # 生物量
X = data.iloc[:, 1:].values  # 指标变量
df = pd.DataFrame(data)
random_seed=44
random_forest_seed=np.random.randint(low=1,high=230)
# 分割数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

运行完这个代码块,可以打印一下,看看变量长什么样。这里可以看到,选取的变量一共有5个,值分别为1.11691217e+01, 4.37000000e+02, 1.31032691e+00, 7.31299972e-01, 1.13057424e-01 可以打开样本表看看,这五个变量对应的值是否正确。
在这里插入图片描述

6.2 选取参数

决策树个数n_estimators

决策树最大深度max_depth,

最小分离样本数(即拆分决策树节点所需的最小样本数) min_samples_split,

最小叶子节点样本数(即一个叶节点所需包含的最小样本数)min_samples_leaf,

最大分离特征数(即寻找最佳节点分割时要考虑的特征变量数量)max_features

# Search optimal hyperparameter
#对六种超参数划定了一个范围,然后将其分别存入了一个超参数范围字典random_forest_hp_range
n_estimators_range=[int(x) for x in np.linspace(start=50,stop=3000,num=60)]
max_features_range=['sqrt','log2',None]
max_depth_range=[int(x) for x in np.linspace(10,500,num=50)]
max_depth_range.append(None)
min_samples_split_range=[2,5,10]
min_samples_leaf_range=[1,2,4,8]random_forest_hp_range={'n_estimators':n_estimators_range,'max_features':max_features_range,'max_depth':max_depth_range,'min_samples_split':min_samples_split_range,'min_samples_leaf':min_samples_leaf_range}
random_forest_model_test_base=RandomForestRegressor()
random_forest_model_test_random=RandomizedSearchCV(estimator=random_forest_model_test_base,param_distributions=random_forest_hp_range,n_iter=200,n_jobs=-1,cv=3,verbose=1,random_state=random_forest_seed)
random_forest_model_test_random.fit(X_train,y_train)best_hp_now=random_forest_model_test_random.best_params_
# Build RF regression model with optimal hyperparameters
random_forest_model_final=random_forest_model_test_random.best_estimator_
print(best_hp_now)

可以看到打印结果
在这里插入图片描述

6.3 误差分布直方图

如果直方图呈现正态分布或者近似正态分布,说明模型的预测误差分布比较均匀,预测性能较好。如果直方图呈现偏斜或者非正态分布,说明模型在某些情况下的预测误差较大,预测性能可能需要进一步改进。

# Predict test set data
random_forest_predict=random_forest_model_test_random.predict(X_test)
random_forest_error=random_forest_predict-y_testplt.figure(1)
plt.clf()
plt.hist(random_forest_error)
plt.xlabel('Prediction Error')
plt.ylabel('Count')
plt.grid(False)
plt.show()

在这里插入图片描述

6.4 变量重要性可视化展示

# 计算特征重要性
random_forest_importance = list(random_forest_model_final.feature_importances_)
random_forest_feature_importance = [(feature, round(importance, 8)) for feature, importance in zip(df.columns[4:], random_forest_importance)]
random_forest_feature_importance = sorted(random_forest_feature_importance, key=lambda x:x[1], reverse=True)# 将特征重要性转换为Pyecharts所需的格式
x_data = [item[0] for item in random_forest_feature_importance]
y_data = [item[1] for item in random_forest_feature_importance]# 绘制柱状图
bar = (Bar().add_xaxis(x_data).add_yaxis("", y_data).reversal_axis().set_series_opts(label_opts=opts.LabelOpts(position="right")).set_global_opts(title_opts=opts.TitleOpts(title="Variable Importances"),xaxis_opts=opts.AxisOpts(name="Importance",axislabel_opts=opts.LabelOpts(rotate=-45, font_size=10)),yaxis_opts=opts.AxisOpts(name_gap=30, axisline_opts=opts.AxisLineOpts(is_show=False)),tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow"))
)bar.render_notebook()

在这里插入图片描述

6.5 对精度进行验证

这里可输出相关的精度值

# Verify the accuracy
random_forest_pearson_r=stats.pearsonr(y_test,random_forest_predict)
random_forest_R2=metrics.r2_score(y_test,random_forest_predict)
random_forest_RMSE=metrics.mean_squared_error(y_test,random_forest_predict)**0.5
print('Pearson correlation coefficient = {0}、R2 = {1} and RMSE = {2}.'.format(random_forest_pearson_r[0],random_forest_R2,random_forest_RMSE))

6.6 预测生物量

注意几个tif数据的nodata值不一样,最好全部都将nodata值设为0,最后得到的biomass图像按照掩膜提取,nodata就变回来啦

import numpy as np
import rasterio
from tqdm import tqdm# 读取五个栅格指标变量数据并整合为一个矩阵
with rasterio.open(r'E:\Sentinel12\yangben\建模\result\nodata\podu.tif') as src:data1 = src.read(1)meta = src.meta
with rasterio.open(r'E:\Sentinel12\yangben\建模\result\nodata\dem.tif') as src:data2 = src.read(1)
with rasterio.open(r'E:\Sentinel12\yangben\建模\result\nodata\lai.tif') as src:data3 = src.read(1)
with rasterio.open(r'E:\Sentinel12\yangben\建模\result\nodata\ndvi.tif') as src:data4 = src.read(1)
with rasterio.open(r'E:\Sentinel12\yangben\建模\result\nodata\pvi.tif') as src:data5 = src.read(1)X = np.stack((data1, data2, data3, data4, data5), axis=-1)# 清洗输入数据
X_2d = X.reshape(-1, X.shape[-1])
# 检查数据中是否存在 NaN 值
print(np.isnan(X_2d).any())  # True# 将 nodata 值替换为0
X_2d[np.isnan(X_2d)] = 0# 使用已经训练好的随机森林模型对整合后的栅格指标变量数据进行生物量的预测
y_pred = []
for i in tqdm(range(0, X_2d.shape[0], 10000)):y_pred_chunk = random_forest_model_test_random.predict(X_2d[i:i+10000])y_pred.append(y_pred_chunk)
y_pred = np.concatenate(y_pred)# 将预测结果保存为一个新的栅格数据
with rasterio.open(r'E:\Sentinel12\yangben\建模\result\biomass_v5.tif', 'w', **meta) as dst:dst.write(y_pred.reshape(X.shape[:-1]), 1)
print("预测结束")

运行之后会在下面出现进度条,进度条走完了就代码预测完了
在这里插入图片描述

七、生物量制图

7.1. 将得到的biomass.tif文件按掩膜提取

 掩膜文件选择用于预测的tif文件,目的是将nodata值还原回来。

7.2. 提取森林掩膜区域

[参考链接](https://www.bilibili.com/video/BV1qv4y1A75B?p=10&vd_source=ddb0eb9d8fde0d0629fc9f25dc6915e5) 
  • 这里需要全球土地覆盖10米的更精细分辨率观测和监测(FROM-GLC10)数据。

  • 我们在GEE平台上下载研究区的GLC10图,参考链接

  1. 在 Google Earth Engine Code Editor 中搜索“ESA Global Land Cover 10m v2.0.0”并加载该数据集。
var glc = ee.Image('ESA/GLOBCOVER_L4_200901_200912_V2_3');
  1. 定义您感兴趣的区域。
    这里的table需要先将shp文件上传到平台,再点那个小箭头导入
    在这里插入图片描述
    这里就会有table出现
    在这里插入图片描述
var geometry = table;
  1. 使用 Image.clip() 函数将图像裁剪为您感兴趣的区域。
var clipped = glc.clip(geometry);
  1. 使用 Export.image.toDrive() 函数导出图像。以下代码将图像导出到您的 Google Drive 中。
Export.image.toDrive({image: clipped,description: 'GLC',folder: 'my_folder',scale: 10,region: geometry
});

其中,description 是导出图像的名称,folder 是导出图像的文件夹,scale 是导出图像的分辨率,region 是导出图像的区域。

  1. 点击“Run”按钮运行代码。代码运行完成后,您可以在 Google Drive 中找到导出的图像文件。
  • 20序号代表森林,按属性提取,可以把森林提取出来,按属性提取工具。
    在这里插入图片描述
    将生物量.tif按照掩膜tif掩膜即可得到森林区域的生物量。

八. 需要注意的点

  1. 每个栅格变量数据一定要保持行数和列数一致,这不仅是为了”多值提取至点“等一一对应,更是为了最后估算生物量的时候生成二维矩阵输入模型,保证输入数据的维度一致。
  2. 第一步的前提是第二部,投影!投影!投影!重要的事情说三遍,一定要在相同坐标系下面
  3. 注意nodata值的处理,最好所有的影像nodata设置为0,这样最后输入模型中可以减少计算量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/18036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抖音引流推广的几个方法,抖音全自动引流脚本软件详细使用教学

大家好我是你们的小编一辞脚本&#xff0c;今天给大家分享新的知识&#xff0c;很开心可以在CSDN平台分享知识给大家,很多伙伴看不到代码我先录制一下视频 在给大家做代码&#xff0c;给大家分享一下抖音引流脚本的知识和视频演示 不懂的小伙伴可以认真看一下&#xff0c;我们…

【C++】总结9

文章目录 C从源代码到可执行程序经过什么步骤静态链接和动态链接类的对象存储空间C的内存分区内存池在成员函数中调用delete this会出现什么问题&#xff1f;如果在类的析构函数中调用delete this&#xff0c;会发生什么&#xff1f; C从源代码到可执行程序经过什么步骤 预处理…

java学习路程之篇六、进阶知识、常用API、Arrays工具类、冒泡排序、选择排序、二分查找、正则表达式

文章目录 1、Arrays工具类2、冒泡排序3、选择排序4、二分查找5、正则表达式 1、Arrays工具类 2、冒泡排序 3、选择排序 4、二分查找 5、正则表达式

【Maven】Nexus3上传maven依赖jar

后端依赖 上次说到前端的批量tgz文件上传私服&#xff0c;其实服务端也有类似情况&#xff0c;我们有个私服也需要进行上传到私服&#xff0c;这里做个记录。因为上次有个小细节没注意白白传错了一遍&#xff0c;这里重新记录总结一下。 # 查看一下结构 $ tree -L 2 . |-- re…

【vue】 Tinymce 富文本编辑器 不想让上传的图片转换成base64,而是链接

前言&#xff1a;最近项目上需要使用富文本编辑器&#xff0c;觉得tinymce很不错就用了&#xff0c;具体怎么在项目中使用参考 【vue】 vue2 中使用 Tinymce 富文本编辑器 【vue】 Tinymce 数据 回显问题 | 第一次正常回显后面&#xff0c;显示空白bug不能编辑 这两天又遇到了…

Windows下RocketMQ的启动

下载地址&#xff1a;下载 | RocketMQ 解压后 一、修改runbroker.cmd 修改 bin目录下的runbroker.cmd set "JAVA_OPT%JAVA_OPT% -server -Xms2g -Xmx2g" set "JAVA_OPT%JAVA_OPT% -XX:MaxDirectMemorySize15g" set "JAVA_OPT%JAVA_OPT% -cp %CLASSP…

八大排序算法--希尔排序(动图理解)

目录 希尔排序 概念 算法思路 动画演示 代码如下 复杂度分析 时间复杂度测试 运行结果 完整代码 创作不易&#xff0c;如果本篇博客对您有一定的帮助&#xff0c;大家记得留言点赞哦。 希尔排序 概念 希尔排序是插入排序的一种&#xff0c;是对直接插入排序的优化。其…

ChinaJoy 2023微星雷鸟17游戏本震撼发布:搭载AMD锐龙9 7945HX首发8499元

ChinaJoy 2023展会中微星笔记本再次给大家带来惊喜&#xff0c;发布了搭载AMD移动端16大核的旗舰游戏本&#xff1a;雷鸟17&#xff0c;更重要的这样一款旗舰性能的游戏本&#xff0c;首发价8499元堪称当今游戏本市场中的“性价比爆款”&#xff01; 本着和玩家一同制霸游戏战场…

k8s概念-StatefulSet

StatefulSet 是用来管理有状态应用的控制器 StatefulSet 用来管理某Pod集合的部署和扩缩&#xff0c; 并为这些 Pod 提供持久存储和持久标识符StatefulSet | KubernetesStatefulSet 运行一组 Pod&#xff0c;并为每个 Pod 保留一个稳定的标识。 这可用于管理需要持久化存储或稳…

【设计模式——学习笔记】23种设计模式——代理模式Proxy(原理讲解+应用场景介绍+案例介绍+Java代码实现)

介绍 基础介绍 代理模式为一个对象提供一个代理对象&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标对象&#xff0c;这样做的好处是&#xff1a;可以在不修改目标对象代码的基础上&#xff0c;增强额外的功能操作&#xff0c;即扩展目标对象的功能被代理的对象…

牛客网Verilog刷题——VL52

牛客网Verilog刷题——VL52 题目答案 题目 请编写一个十进制计数器模块&#xff0c;当mode信号为1&#xff0c;计数器输出信号递增&#xff0c;当mode信号为0&#xff0c;计数器输出信号递减。每次到达0&#xff0c;给出指示信号zero。模块的接口信号图如下&#xff1a; 模块的…

Flask学习笔记_异步论坛(四)

Flask学习笔记_异步论坛&#xff08;四&#xff09; 1.配置和数据库链接1.exts.py里面实例化sqlalchemy数据库2.config.py配置app和数据库信息3.app.py导入exts和config并初始化到app上 2.创建用户模型并映射到数据库1.models/auth.py创建用户模型2.app.py导入模型并用flask-mi…

教师工作量管理系统Springmvc+Spring+Mybatis课程工作量教室java源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 教师工作量管理系统SpringmvcSpringMybatis 系统有1权…

快速开发人脸识别系统Java版本

简介&#xff1a; 先说下什么是人脸识别系统&#xff1a;举个例子&#xff0c;公司门口有个人脸识别系统&#xff0c;员工站到门口&#xff0c;看着摄像头&#xff0c;大屏幕上会抓拍到你的人脸&#xff0c;然后和公司的员工照片库里的照片比对&#xff0c;比对成功就提示&…

ThreadLocal原理

ThreadLocal原理 ThreadLocal对象new出来存放到堆中&#xff0c;ThreadLocal引用是存放在栈里 Thread 类有个 ThreadLocalMap 成员变量&#xff0c;Map的key是Threadlocal 对象&#xff0c;value是你要存放的线程局部变量。 public void set(T value) {//获取当前线程Thread&…

python爬虫(四)_urllib2库的基本使用

本篇我们将开始学习如何进行网页抓取&#xff0c;更多内容请参考:python学习指南 urllib2库的基本使用 所谓网页抓取&#xff0c;就是把URL地址中指定的网络资源从网络流中读取出来&#xff0c;保存到本地。在Python中有很多库可以用来抓取网页&#xff0c;我们先学习urllib2。…

从零开始学python(十三)爬虫工程师自动化和抓包

前言 回顾之前讲述了python语法编程 必修入门基础和网络编程&#xff0c;多线程/多进程/协程等方面的内容&#xff0c;后续讲到了数据库编程篇MySQL&#xff0c;Redis&#xff0c;MongoDB篇&#xff0c;和机器学习&#xff0c;全栈开发&#xff0c;数据分析&#xff0c;爬虫数…

Go项目实现日志按时间及文件大小切割并压缩

关于日志的一些问题: 单个文件过大会影响写入效率&#xff0c;所以会做拆分&#xff0c;但是到多大拆分? 最多保留几个日志文件&#xff1f;最多保留多少天&#xff0c;要不要做压缩处理&#xff1f; 一般都使用 lumberjack[1]这个库完成上述这些操作 lumberjack //info文件wr…

uniapp实现地图点聚合

点聚合的最重要的一个地方是在 markers 中添加 joinCluster true 这个重要的属性&#xff0c;否则将无法开启点聚合功能。 其实在uniapp的官方文档里体现的不是那么清楚&#xff0c;但是在小程序文档提示的就相当清楚。 实现效果如下&#xff1a; 重点&#xff1a;需要编译在小…

【密码学】四、SM4分组密码算法

SM4分组密码算法 1、概述1.1初始变量算法1.2密钥扩展算法1.3轮函数F1.3.1合成置换T1.3.2S盒 2、算法设计原理2.1非平衡Feistel网络2.2T变换2.2.1非线性变换τ2.2.2线性变换L2.2.3基础置换 2.3密钥扩展算法的设计 1、概述 SM4分组密码算法是一种迭代分组密码算法&#xff0c;采…