Python在地球科学中的应用:从数据处理到模型集成的全流程实践

Python在地球科学中的应用:从数据处理到模型集成的全流程实践 1. 从数据到洞察Python如何重塑地球科学工作流如果你在地球科学、环境科学或者气象水文领域工作还在用Excel手动处理站点数据用ArcGIS的图形界面一遍遍点击处理遥感影像或者对着WRF模式输出的海量NetCDF文件发愁那这篇文章就是为你准备的。我在这行干了十几年从最初用Fortran和IDL到后来全面转向Python亲眼见证了这门语言如何把一个依赖昂贵商业软件、流程割裂的领域变成了一个高效、可复现、且充满创造力的开放科学 playground。今天我们不谈空洞的理论就聊聊怎么用Python这把“瑞士军刀”实实在在地解决遥感数据处理、站点数据分析、模式后处理以及生态模型运行这些日常工作中的硬骨头。核心就一句话Python不是来替代你的专业知识的它是来解放你让你从重复、繁琐的“数据搬运工”角色中解脱出来把精力真正放在科学问题本身。无论是从卫星下载的TB级遥感影像还是遍布全国的自动气象站数据亦或是超级计算机跑出来的复杂模式结果Python都能提供一套统一、灵活且强大的工具链来驾驭它们。你会发现很多过去需要跨多个软件、写很多脚本才能完成的流程现在用Python的几个核心库就能优雅地串联起来。更重要的是你构建的每一个处理脚本、分析流程都是一份可共享、可验证、可改进的“数字实验记录”这对于推动研究的透明度和可复现性至关重要。2. 工具箱盘点地球科学领域的Python核心武器库工欲善其事必先利其器。在深入具体场景前我们必须先认识一下Python在地球科学领域的“明星库”。它们各有专长组合起来威力无穷。2.1 数据处理的基石NumPy, SciPy 与 Pandas任何数据分析都绕不开它们。NumPy提供了高性能的多维数组对象和数学函数是几乎所有科学计算库的底层基础。处理遥感影像三维数组高度x宽度x波段或模式格点数据四维数组时间x层次x纬度x经度时NumPy数组是你的基本操作单元。Pandas则是处理表格型和时间序列数据的利器。对于站点观测数据——比如全国几百个气象站逐小时的气温、降水记录——Pandas的DataFrame结构堪称完美。它能轻松处理缺失值、进行时间重采样例如将小时数据聚合为日数据、数据对齐和连接其效率远非Excel可比。SciPy建立在NumPy之上提供了更高级的科学计算模块包括积分、优化、线性代数、统计和信号处理等。当你需要进行空间插值如将离散站点数据插值到规则网格、拟合趋势线或进行假设检验时SciPy是你的首选。2.2 地理空间数据的王者GDAL, Rasterio 与 GeoPandas这是处理遥感数据和矢量数据的核心。GDAL是一个强大的地理空间数据转换库支持读写几乎所有的栅格和矢量数据格式如GeoTIFF, NetCDF, HDF, Shapefile。虽然它本身是C库但通过osgeo.gdal这个Python绑定我们可以直接调用其所有功能。它是许多高级库的底层依赖。Rasterio是一个更“Pythonic”的栅格数据处理库它简化了GDAL的许多复杂操作。用Rasterio读取、写入、裁剪、重投影遥感影像变得异常简单直观。它的API设计非常友好是处理遥感栅格数据的现代标准。GeoPandas扩展了Pandas使其能够处理地理空间矢量数据。它内部使用Shapely进行几何操作使用Fiona进行文件读写。你可以像操作Pandas DataFrame一样操作地理数据表每一行是一个地理要素如一个省份多边形、一个站点点位置并附带一个几何列。进行空间连接、缓冲区分析、地图可视化都非常方便。2.3 气候与大气科学的标配xarray, NetCDF4 与 Cartopy对于处理WRF等数值模式输出、再分析资料如ERA5或任何NetCDF/HDF格式的多维网格数据xarray是革命性的工具。它引入了“带标签的数组”概念将维度坐标如经度、纬度、时间、气压层和数据变量紧密关联。你可以通过名称而不是索引位置来选择和切片数据这大大增强了代码的可读性和可靠性。xarray也集成了Dask可以轻松处理远超内存大小的数据集。NetCDF4库是读写NetCDF文件的基础。虽然xarray通常作为更高级的接口但有时直接使用netCDF4进行底层操作或处理非标准文件也是必要的。Cartopy是专业的地图制图库专门用于绘制地理空间数据。它支持多种地图投影可以轻松添加海岸线、国界、河流等地理要素并与Matplotlib无缝集成制作出版级的地图可视化结果。2.4 可视化与交互Matplotlib, Seaborn 与 HoloViewsMatplotlib是Python绘图的基石功能极其强大几乎可以绘制任何你想要的静态图形。其缺点是比较底层制作复杂的图表需要较多代码。Seaborn基于Matplotlib提供了更高级的统计图形接口默认样式更美观绘制分布图、热力图、多变量关系图等非常便捷。对于需要探索性数据分析或制作交互式仪表盘HoloViews和Panel是很好的组合。它们可以让你用较少的代码创建交互式图表并链接多个视图方便动态探索高维数据。2.5 机器学习与深度学习Scikit-learn, TensorFlow/PyTorch现代地球科学研究越来越多地融入机器学习方法。Scikit-learn提供了完整的传统机器学习算法分类、回归、聚类、降维接口统一文档优秀是入门和实践的首选。对于更复杂的深度学习模型如用于卫星图像语义分割的U-Net或用于气象预报的卷积LSTM网络TensorFlow和PyTorch是两个主流框架。它们为构建和训练神经网络提供了完整的生态系统。3. 实战场景一遥感数据处理全流程解析遥感数据是地球科学的眼睛。我们从数据下载到最终信息提取走一遍典型的Python流程。3.1 数据获取与预处理首先数据从哪里来对于公开数据我们可以用Python脚本自动化下载。例如使用requests库和pydap库访问NASA或ESA的数据服务器。import requests from netCDF4 import Dataset import io # 示例从NASA GES DISC下载MODIS数据需有权限 url ‘https://disc.gsfc.nasa.gov/your_data_url’ response requests.get(url, auth(‘your_username‘, ’your_password‘)) # 将响应的内容读取为NetCDF数据集 nc_data Dataset(‘in_memory.nc‘, memoryresponse.content)下载的原始数据如L1级通常需要经过辐射定标、大气校正等预处理才能得到地表反射率或温度等物理量。虽然这些步骤有专业软件如ENVI但Python也能通过rasterio和numpy进行核心计算。例如Landsat数据的大气校正可以使用py6s一个6S大气辐射传输模型的接口来模拟大气影响并进行校正。3.2 影像裁剪、镶嵌与重投影研究区域很少恰好是一景影像的范围。我们需要裁剪和镶嵌。import rasterio from rasterio.mask import mask import geopandas as gpd # 1. 读取研究区矢量边界 study_area gpd.read_file(‘study_area.shp‘) # 2. 读取遥感影像 with rasterio.open(‘satellite_image.tif‘) as src: # 3. 根据矢量边界裁剪 out_image, out_transform mask(src, study_area.geometry, cropTrue) # 4. 更新元数据并写入新文件 out_meta src.meta.copy() out_meta.update({ “height“: out_image.shape[1], “width“: out_image.shape[2], “transform“: out_transform }) with rasterio.open(‘clipped_image.tif‘, ‘w‘, **out_meta) as dest: dest.write(out_image)如果有多景影像需要拼接镶嵌可以使用rasterio.merge模块。重投影则使用rasterio.warp模块这对于将不同坐标系的数据统一到同一基准下至关重要。3.3 信息提取从像素到参数这是遥感的核心。以计算归一化植被指数NDVI为例import numpy as np # 假设红波段和近红外波段数据已读取为数组 red_band, nir_band # 注意处理除零和无效值 ndvi (nir_band.astype(float) - red_band.astype(float)) / (nir_band red_band 1e-10) # 加一个小量防止除零 # 将无效值如云、水设为NaN ndvi[(nir_band 0) (red_band 0)] np.nan # 将NDVI值限制在[-1, 1]的合理范围内 ndvi np.clip(ndvi, -1.0, 1.0)更复杂的参数反演如地表温度、叶面积指数、蒸散发等可能需要构建查找表或调用物理模型。Python可以整合这些计算流程。例如使用PySEBAL或PyMETRIC这样的开源库来估算区域蒸散发。3.4 时间序列分析与变化检测对于多时相数据如MODIS每日数据我们可以构建像素级的时间序列。import xarray as xr import pandas as pd # 假设我们已经将多年的NDVI GeoTIFF文件堆叠成一个多波段文件或直接读取多时相NetCDF # 使用xarray打开数据它自动识别时间维度 ds xr.open_dataset(‘ndvi_time_series.nc‘) ndvi_series ds[‘ndvi‘] # 这是一个三维DataArray (time, y, x) # 针对某个像素点提取时间序列 pixel_ts ndvi_series.sel(x120.5, y30.2, method‘nearest‘) # 可以将其转换为Pandas Series进行进一步分析 ts_pd pixel_ts.to_pandas() # 进行平滑如Savitzky-Golay滤波以去除噪声 from scipy.signal import savgol_filter ts_smooth savgol_filter(ts_pd.values, window_length5, polyorder2) # 变化检测比较两个时期均值 period1_mean ndvi_series.sel(timeslice(‘2000-01‘, ‘2005-12‘)).mean(dim‘time‘) period2_mean ndvi_series.sel(timeslice(‘2015-01‘, ‘2020-12‘)).mean(dim‘time‘) change period2_mean - period1_mean实操心得处理长时间序列遥感数据时云污染是最大干扰。务必使用高质量的数据集如MODIS的MOD13Q1是16天合成的NDVI产品已部分去云或采用更先进的去云算法如whittaker smoother或BFAST。直接对原始时间序列做分析结果可能噪声极大。4. 实战场景二站点数据与遥感数据的融合之道站点数据精度高但空间不连续遥感数据空间连续但受限于分辨率和反演精度。将二者结合是提升分析质量的关键。4.1 站点数据的规整化处理站点数据通常以CSV或Excel格式提供格式五花八门。第一步是用Pandas将其清洗规整。import pandas as pd # 读取数据 df pd.read_csv(‘weather_stations.csv‘, encoding‘gbk‘) # 注意中文编码 # 查看基本信息 print(df.info()) print(df.head()) # 数据清洗 # 1. 重命名列 df df.rename(columns{‘观测时间‘: ‘time‘, ‘站号‘: ‘station_id‘, ‘气温(℃)‘: ‘temp‘}) # 2. 将时间列转换为datetime格式 df[‘time‘] pd.to_datetime(df[‘time‘]) # 3. 设置时间为索引 df.set_index(‘time‘, inplaceTrue) # 4. 处理缺失值可以用前后时刻插值但需谨慎 df[‘temp‘] df[‘temp‘].interpolate(method‘time‘, limit3) # 5. 去除明显异常值如气温50或-50 df df[(df[‘temp‘] -50) (df[‘temp‘] 50)] # 按站点分组并重采样为日平均数据 daily_temp df.groupby(‘station_id‘)[‘temp‘].resample(‘D‘).mean().reset_index()4.2 空间插值从点到面我们需要将离散的站点数据插值到连续的网格上以便与遥感数据对比或作为模型输入。常用方法包括反距离权重IDW、克里金Kriging等。from scipy.interpolate import griddata import numpy as np # 假设我们有站点坐标和对应的温度值 stations pd.DataFrame({ ‘lon‘: [116.4, 117.2, 115.8, ...], ‘lat‘: [39.9, 40.1, 39.5, ...], ‘temp‘: [25.3, 24.8, 26.1, ...] }) # 创建目标网格与遥感影像网格对齐 lon_grid, lat_grid np.meshgrid( np.linspace(115.0, 118.0, 300), # 经度范围300个点 np.linspace(39.0, 41.0, 200) # 纬度范围200个点 ) # 使用线性插值也可选择‘cubic‘或‘nearest‘ temp_grid griddata( (stations[‘lon‘], stations[‘lat‘]), # 已知点坐标 stations[‘temp‘], # 已知点值 (lon_grid, lat_grid), # 目标网格 method‘linear‘, fill_valuenp.nan # 对无法插值的区域填充NaN )对于更专业的地统计插值如克里金法推荐使用pykrige库。4.3 尺度匹配与验证遥感数据像元代表的是几百米到几公里范围内的平均值而站点数据是点测量。直接比较是不公平的。通常的做法是将遥感数据在站点位置处提取一个窗口如3x3像元的平均值与站点观测值进行比较计算相关系数、均方根误差等指标。import rasterio import geopandas as gpd from shapely.geometry import Point # 站点位置转为GeoDataFrame geometry [Point(xy) for xy in zip(stations[‘lon‘], stations[‘lat‘)] gdf_stations gpd.GeoDataFrame(stations, geometrygeometry, crs“EPSG:4326“) # 读取遥感地表温度数据 with rasterio.open(‘lst.tif‘) as src: # 将站点坐标投影到遥感影像的坐标系 gdf_stations_proj gdf_stations.to_crs(src.crs) # 采样提取每个站点位置的像元值最近邻 sampled_values [] for geom in gdf_stations_proj.geometry: # 将地理坐标转为影像的行列号 row, col src.index(geom.x, geom.y) # 读取该像元值如果是多波段则读取所有波段 value src.read(1, window((row, row1), (col, col1)))[0,0] sampled_values.append(value) stations[‘lst_sampled‘] sampled_values # 计算统计指标 correlation stations[[‘temp‘, ‘lst_sampled‘]].corr().iloc[0,1] rmse np.sqrt(((stations[‘temp‘] - stations[‘lst_sampled‘])**2).mean())踩坑实录尺度效应是验证中的最大陷阱。在异质地表如城市混合了建筑、植被、水体一个像元内的变异性可能很大站点值可能完全不能代表像元均值。此时选择均质下垫面如大块农田、水体的站点进行验证会更可靠。此外时间同步性也很关键遥感过境时间与站点观测时间要尽可能接近。5. 实战场景三WRF模式数据后处理实战指南WRF模式输出通常是多个时间步、多个层次、多个变量的NetCDF文件数据量巨大。后处理的目标是从中提取有用的信息并可视化。5.1 高效读取与数据探索使用xarray打开WRF输出文件是最佳选择。import xarray as xr import numpy as np # 打开单个文件 ds xr.open_dataset(‘wrfout_d01_2023-07-01_00:00:00‘) print(ds) # 查看所有变量 print(list(ds.data_vars)) # 查看维度信息 print(ds.dims) # 打开多个时间序列文件时间拼接 files sorted(glob.glob(‘wrfout_d01_2023-07-*‘)) ds_multi xr.open_mfdataset(files, combine‘by_coords‘, parallelTrue) # 并行读取加速xarray的惰性加载lazy loading特性意味着它不会立即将所有数据读入内存只有在实际计算时才会读取这对处理海量数据至关重要。5.2 常用气象要素提取与计算WRF输出变量繁多有些需要计算才能得到。例如计算2米气温、10米风场、海平面气压等。# 假设我们已经读取了数据集 ds # 提取2米气温T2和2米露点温度TD2 t2 ds[‘T2‘] - 273.15 # 从开尔文转换到摄氏度 td2 ds[‘TD2‘] - 273.15 # 计算相对湿度 (一个简化公式更精确的需用饱和水汽压公式) rh2 100 * (np.exp((17.625 * td2) / (243.04 td2)) / np.exp((17.625 * t2) / (243.04 t2))) # 提取10米U、V风分量并计算风速和风向 u10 ds[‘U10‘] v10 ds[‘V10‘] wind_speed_10m np.sqrt(u10**2 v10**2) wind_dir_10m 180 (180/np.pi) * np.arctan2(u10, v10) # 转换为气象风向0°为正北 # 计算海平面气压SLPWRF通常有现成变量‘PSFC‘地表气压但海平面气压需要算法 # 这里假设有‘P‘气压扰动和‘PB‘基础态气压以及‘PH‘和‘PHB‘位势高度 # 计算全气压 pressure ds[‘P‘] ds[‘PB‘] # 单位为Pa # 计算位势高度 height (ds[‘PH‘] ds[‘PHB‘]) / 9.81 # 转换为米 # 将地表气压插值到海平面需要更复杂的算法有时模式直接输出‘SLP‘变量5.3 垂直剖面与时空剖面绘制分析天气系统结构时垂直剖面图必不可少。import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature # 假设我们要画一条从点A(lat1, lon1)到点B(lat2, lon2)的垂直剖面 lat1, lon1 30.0, 110.0 lat2, lon2 40.0, 120.0 # 使用xarray的interp方法沿着这条线插值 # 首先我们需要创建这条线上的一系列点 from metpy.interpolate import cross_section # Metpy是一个气象专用包其cross_section函数非常方便 # 假设data是包含气压层数据的xarray Dataset import metpy.calc as mpcalc from metpy.units import units # 为数据添加单位metpy需要 data data.metpy.parse_cf() # 创建剖面 cross cross_section(data, start(lat1, lon1), end(lat2, lon2)) # 绘制位温剖面 fig, ax plt.subplots(figsize(12, 6)) # 绘制填色图例如垂直速度 cf ax.contourf(cross[‘lon‘], cross[‘pressure‘], cross[‘w‘], cmap‘RdBu_r‘, levels20) # 绘制等值线例如位温 cs ax.contour(cross[‘lon‘], cross[‘pressure‘], cross[‘theta‘], colors‘k‘, linewidths0.5) ax.clabel(cs, fmt‘%d‘) ax.invert_yaxis() # 气压坐标从上到下增大 ax.set_ylabel(‘Pressure (hPa)‘) ax.set_xlabel(‘Longitude‘) plt.colorbar(cf, label‘Vertical Velocity (Pa/s)‘) plt.title(‘Vertical Cross-section‘) plt.show()时空剖面Hovmöller图对于分析系统的移动和演变非常有用通常是将某个变量沿某一纬度或经度平均后随时间变化作图。5.4 区域统计与输出我们常需要计算某个区域如京津冀的平均降水量、最高气温等。import regionmask # 定义区域多边形例如用经纬度列表定义一个矩形 lon_bounds [115.5, 117.5] lat_bounds [39.5, 40.5] # 创建一个掩膜 mask regionmask.defined_regions.natural_earth.countries_110.mask(ds.lon, ds.lat) # 或者自定义多边形 from shapely.geometry import Polygon polygon Polygon([(115.5, 39.5), (117.5, 39.5), (117.5, 40.5), (115.5, 40.5)]) region regionmask.Regions([polygon]) mask region.mask(ds.lon, ds.lat) # 应用掩膜计算区域平均 precip ds[‘RAINNC‘] # 累积降水 precip_regional precip.where(mask 0) # mask0 对应我们定义的区域 precip_mean_ts precip_regional.mean(dim[‘south_north‘, ‘west_east‘])注意事项WRF模式使用交错网格Arakawa C网格速度变量U, V和标量变量T, QVAPOR的格点位置不同。在计算某些需要速度场和标量场结合的量如水平平流时必须先将它们插值到同一格点上。wrf-python这个库提供了大量函数来处理WRF数据的这些特殊性非常推荐。6. 实战场景四驱动与运行生态模型以BIOME-BGC为例生态模型如BIOME-BGC, LPJ-GUESS, DALEC通常用于模拟生态系统的碳、氮、水循环。Python在这里的角色主要是准备驱动数据、参数化、运行模型或调用模型可执行文件、以及分析输出结果。6.1 驱动数据准备生态模型需要气象驱动数据逐日或逐时、土壤数据、植被类型和参数。我们需要将各种来源的数据处理成模型要求的特定格式通常是ASCII或NetCDF。import pandas as pd import numpy as np # 假设我们有气象站数据生成的逐日驱动文件CSV # 列包括年月日最高温(Tmax)最低温(Tmin)降水(Precip)太阳辐射(Srad)水汽压(VPD)等 df_drive pd.read_csv(‘meteo_daily.csv‘) # BIOME-BGC的经典气象输入格式是空格分隔的ASCII每行代表一天 # 顺序通常是年日平均温度降水太阳辐射VPD... # 注意日序是从1到365/366 df_drive[‘doy‘] pd.to_datetime(df_drive[[‘year‘, ‘month‘, ‘day‘]]).dt.dayofyear # 计算日平均温度假设Tmax和Tmin df_drive[‘tavg‘] (df_drive[‘tmax‘] df_drive[‘tmin‘]) / 2.0 # 选择需要的列并重排顺序 output_data df_drive[[‘year‘, ‘doy‘, ‘tavg‘, ‘precip‘, ‘srad‘, ‘vpd‘]] # 保存为空格分隔的文本 np.savetxt(‘biome_bgc_meteo.txt‘, output_data.values, fmt‘%d %d %.2f %.2f %.2f %.3f‘)对于空间化的模型运行我们需要为每个格点准备一套驱动数据。这通常是通过将再分析资料如CRU, ERA5插值到模型格网并用Python批量生成成千上万个输入文件。6.2 模型参数化与配置文件生成生态模型有大量参数如最大光合速率、叶片寿命、碳氮比等。这些参数因植被类型而异。我们需要根据研究区域的植被图为每个像元分配对应的参数文件。import yaml # 或 import configparser # 模型通常有一个主配置文件INI格式或YAML格式控制运行年份、输入输出路径、参数文件等 config { ‘simulation‘: { ‘start_year‘: 2000, ‘end_year‘: 2020, ‘spinup_years‘: 500 }, ‘paths‘: { ‘meteo_file‘: ‘./input/met_001.txt‘, ‘param_file‘: ‘./params/evergreen_needleleaf.cfg‘, ‘output_file‘: ‘./output/out_001.nc‘ }, ‘options‘: { ‘co2_constant‘: 380.0, ‘nitrogen_deposition‘: ‘on‘ } } # 将配置写入YAML文件 with open(‘run_config.yml‘, ‘w‘) as f: yaml.dump(config, f, default_flow_styleFalse) # 对于不同站点或像元我们可以用循环批量生成配置文件 site_ids [‘001‘, ‘002‘, ‘003‘] for sid in site_ids: config[‘paths‘][‘meteo_file‘] f‘./input/met_{sid}.txt‘ config[‘paths‘][‘output_file‘] f‘./output/out_{sid}.nc‘ # ... 根据sid选择不同的参数文件 with open(f‘run_config_{sid}.yml‘, ‘w‘) as f: yaml.dump(config, f)6.3 批量运行与作业提交对于单点模拟可以用Python的subprocess模块调用模型可执行文件。import subprocess import os from concurrent.futures import ProcessPoolExecutor def run_model(config_file): 运行一次模型模拟 # 假设模型可执行文件是 biome_bgc.exe它接受一个配置文件作为参数 cmd [‘./biome_bgc.exe‘, config_file] result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: print(f“Error running {config_file}: {result.stderr}“) return False else: print(f“Successfully ran {config_file}“) return True # 串行运行慢 config_files [f‘run_config_{sid}.yml‘ for sid in site_ids] for cfg in config_files: run_model(cfg) # 并行运行快充分利用多核CPU with ProcessPoolExecutor(max_workers4) as executor: results list(executor.map(run_model, config_files))对于需要在超算上运行的大规模模拟Python可以用于生成PBS或Slurm作业提交脚本。6.4 结果分析与综合模型输出通常是时间序列的NetCDF或文本文件。我们用xarray或pandas读取并进行分析。import xarray as xr import matplotlib.pyplot as plt # 读取模型输出 ds_out xr.open_dataset(‘./output/out_001.nc‘) # 查看变量 print(ds_out.data_vars) # 提取总初级生产力GPP时间序列 gpp_ts ds_out[‘gpp‘].mean(dim[‘y‘, ‘x‘]) # 如果是空间输出先空间平均 # 转换为Pandas Series并绘图 gpp_ts.to_pandas().plot(figsize(10,4)) plt.ylabel(‘GPP (g C m-2 day-1)‘) plt.xlabel(‘Date‘) plt.title(‘Simulated Gross Primary Productivity‘) plt.show() # 计算多年平均值 gpp_annual_mean gpp_ts.groupby(‘time.year‘).mean() # 分析年际趋势 from scipy import stats years gpp_annual_mean.year.values values gpp_annual_mean.values slope, intercept, r_value, p_value, std_err stats.linregress(years, values) print(f“Trend: {slope:.4f} g C m-2 yr-1 per year, p-value: {p_value:.4f}“)经验之谈生态模型模拟最大的不确定性往往来自参数和驱动数据而非模型结构本身。务必进行敏感性分析和参数优化。Python的SALib库可用于全局敏感性分析scipy.optimize可用于参数率定。在批量运行前先用单个点进行试运行确保所有输入文件格式正确、单位一致。模型输出通常包含数十个变量事先明确你的科学问题集中分析关键变量如NPP、蒸散、土壤水分避免陷入数据海洋。