简介:面向GIS学习者与从业者的一套ArcGIS空间分析实例及练习数据,覆盖第3至第8章由浅入深的空间分析技术,可供系统训练缓冲区、叠置、网络、地形、栅格分析及空间统计建模等核心方法,解决理论学习后缺少可操作案例的问题。压缩包内共657个文件,以shp/shx/dbf等矢量数据、adf/img等栅格数据为主,同时包含mxd地图文档、mdb地理数据库,以及txt、doc说明文件,整体约26.4MB,RAR格式便于本地解压使用。内容按章节组织,每章配有练习数据、操作步骤与预期结果,从数据加载、分析处理到结果制图均有完整流程可循;其中还涉及ArcGIS MXD工程文件与地理数据库,可直接打开练习,适合城市规划、环境保护、灾害响应等实际应用场景。已有393人学习下载,可作为高校GIS课程实验、自学入门或项目实战前的配套参考。
1. 打开《ArcGIS空间分析实例与练习数据3-8章》之前,先把这三件事想清楚
第一次拿到这类练习资料的人,最容易做的一件事是把数据直接拖进地图框里看个热闹,而真正能把分析结果和教材对上的,往往是先把目录结构、坐标系和备份这三件事处理干净的人。3-8章正好是整套资料里空间分析能力最集中的一段:矢量缓冲区与叠加、栅格计算与重分类、坡度坡向等表面分析、地形水文、网络分析,以及插值与结果验证。配套的练习数据如果只被当成“点击用的原料”,练完就忘;把它整理成一套可以反复执行、能换数据重跑的实验目录,后面每一章都能在几分钟内跑完,也能让错误可追溯。这篇文章适合三类人:正在用这些章节准备考试或课程作业的人,自学空间分析但缺一套完整数据链的人,以及工作中需要对空间分析结果负责的一线GIS从业者。
2. 先别急着做叠加分析:把3-8章练习数据整理成能重复执行的实验目录
2.1 练习数据的组成和目录管理
我拿到这类配套资料,第一件事不是双击打开工程文件,而是先看整个目录。第3到第8章的练习数据通常以Shapefile、文件地理数据库、栅格影像、EXCEL属性表和工程文档几种形式混在一起,有的按章节建文件夹,有的把所有数据平铺在一个大目录里。平铺目录看起来省事,实际跑起来最痛苦:缓冲结果、叠加结果、重分类结果全堆在一起,你根本分不清哪个是原始数据、哪个是中间产品,哪一步的输出又覆盖了上一步的输入。
常见做法是先建立三层目录:src放原始数据,analysis.gdb放中间成果,output放最终图表和图层。src目录建好之后,第一件事是把整套原始数据复制一份进去,然后所有文件属性改成只读,保证后面不管怎么跑,原始数据都不会被覆盖。这不是小题大做。练习数据里一个不显眼的字段被误改,或者一个要素被编辑器里的移动操作碰过,后面的叠加统计结果可能直接对不上。
至于是不是要把数据全部导入文件地理数据库,我的建议是:能导入就导入。Shapefile 有字段名长度限制、属性表大小限制,叠加分析生成的新要素类一旦字段多起来,写回 Shapefile 很容易报错。文件地理数据库analysis.gdb没有这些问题,而且 ArcGIS 对 GDB 的读写效率明显高于散落的 Shapefile。
2.2 坐标系不统一:三个叠加结果全错
3-8章练习数据里经常出现坐标系不一致的情况。有的数据是 WGS84 地理坐标系,范围显示成小数的经纬度,有的是 CGCS2000 高斯投影,范围是几百万米的整数。你从目录里看两个图层叠在一起似乎位置差不多,其实相差可能上千公里。更隐蔽的问题是缓冲区分析:Buffer 距离写“500”,如果输入是地理坐标系,工具会把“500”当成度来处理,而不是米。一度在赤道附近对应约111公里,这个缓冲区结果根本没有实际意义。
快速检查方法是看图层的属性源。如果范围的最小值和最大值在0.000几这个量级,基本可以确定是地理坐标系;如果是六位数或者八位数的范围,那是投影坐标系。分析开始前,把所有矢量数据统一到一个投影坐标系,把栅格数据统一到同一像元大小和范围,是空间分析里成本最低、收益最高的一步。
常见的统一投影做法是选择与你所在地区匹配的高斯投影或 UTM 投影带。比如某个练习区域位于经度120度附近,可以选 CGCS2000 3 Degree GK Zone 39 或 Zone 40。不必死记带号,关键是让投影坐标系和真实地理位置大致吻合,这样距离和面积量纲才可靠。
2.3 用 arcpy 批量整理目录:把备份、导入、投影一次做完
这里给出一段可以直接改路径使用的 arcpy 脚本,作用是遍历练习数据目录里的 Shapefile,把它们全部导入到一个文件地理数据库,并统一投影到目标坐标系。这段代码每次拿到一批新练习数据,我都会改两个路径直接跑。
# 批量整理练习数据:原始Shapefile导入GDB并统一投影 import arcpy import os arcpy.env.overwriteOutput = True # 允许同名覆盖,方便反复重跑 src_dir = r"D:\gis_work\ch3_8\src" # 原始练习数据目录 out_gdb = r"D:\gis_work\ch3_8\analysis.gdb" # 中间成果数据库 target_sr = arcpy.SpatialReference('CGCS2000 3 Degree GK Zone 40') # 1) 不存在才创建文件地理数据库,避免清掉已有成果 if not arcpy.Exists(out_gdb): arcpy.CreateFileGDB_management(os.path.dirname(out_gdb), os.path.basename(out_gdb)) # 2) 遍历目录下所有 Shapefile,按空间参考决定投影还是直接复制 for root, dirs, files in os.walk(src_dir): for f in files: if f.lower().endswith('.shp'): fc = os.path.join(root, f) desc = arcpy.Describe(fc) name = os.path.splitext(f)[0] out_fc = os.path.join(out_gdb, name) if desc.spatialReference.type == 'Projected': arcpy.Copy_management(fc, out_fc) else: arcpy.Project_management(fc, out_fc, target_sr) print('done')这段代码的逻辑说明:先检查文件地理数据库是否存在,不存在才创建,避免误删你之前跑出来的数据;然后遍历src_dir下所有.shp文件,用Describe读取空间参考类型,已经是投影坐标系的直接复制,是地理坐标系或未知坐标系的项目到target_sr。这样处理以后,analysis.gdb里的矢量数据都处于同一坐标系,后面做缓冲区和叠加分析不会因为坐标系打架。
参数说明里有几个关键点:overwriteOutput设置为 True,是为了脚本重跑时不用手动删旧文件;SpatialReference传入字符串名称,如果字符串写错或当前版本不支持,工具会报错,所以建议先打开 ArcGIS 的“投影”工具界面,从下拉框里复制完整的坐标系名称再贴进来;另外要注意不同子目录若有同名 Shapefile,导入 GDB 后可能互相覆盖,出现这种情况时,要么在遍历时给名字加上子目录前缀,要么按章节分开跑。
2.4 环境参数:让两次运行得到完全一致的结果
很多人在练习时发现同一套数据的两次分析结果不一样,或者某个工具在某台电脑上跑出来的结果不相同。这不一定是数据问题,而是环境参数里的默认设置不同。ArcGIS 的环境参数就像全局变量,会影响到所有后续工具的执行方式。我每次分析前固定设置四组参数:当前工作空间、覆盖输出、栅格分析范围、栅格像元大小。
| 环境项 | 推荐设置 | 作用 |
|---|---|---|
| 当前工作空间 | analysis.gdb | 输出默认落到数据库,避免散落 |
| 覆盖输出 | 勾选 | 重跑时不用手动清理旧结果 |
| 处理范围 | 设为 DEM 或研究区栅格 | 保证多次结果范围一致 |
| 像元大小 | 设为分析基准栅格的大小 | 防止插值后像元尺寸漂移 |
在 ArcGIS Pro 里,这些设置在“分析”选项卡下的“环境”中统一修改,修改后保存成配置文件,以后换到别的机器上直接套用。对于《ArcGIS空间分析实例与练习数据3-8章》这类带多个章节的数据,这套配置能保证你在第3章跑出某个范围的结果,第5章换参数重跑时,依然是在同一个盘子、同一个分辨率下去对比,而不是在完全不同的输出范围上做毫无意义的比较。
3. 矢量空间分析:缓冲区与叠加的参数设置和结果查验
3.1 缓冲区半径、融合类型和环形缓冲区怎么搭配
缓冲区分析是3-8章矢量部分最基础也最常用的操作,它的本质是求距离一个要素一定范围内的所有空间集合。看起来就是一个工具的事,但参数选错,结果完全不是一个意思。第一个容易错的是距离单位。缓冲半径应该写成类似“500 Meters”的带单位字符串,而不是裸写一个数字“500”。当输入是地理坐标系时,裸写“500”会被当作500度,结果是一个覆盖全球的圈圈。当输入是投影坐标系时,裸写“500”会被当作500米或500英尺,取决于图层自身定义的线性单位。
第二个容易错的是融合方式。缓冲区工具里的Dissolve参数有三个常用值:ALL、NONE和字段列表。ALL会把所有要素的缓冲区合并成一个大整体,重叠部分不留边界,适合生成禁建区、影响范围这类宏观边界;NONE保留每个输入要素对应的独立缓冲区,重叠区域各自保留,适合后续按要素组做统计。比如要统计每个学校1000米范围内有多少个公交站,你就必须用NONE,因为要保留学校的属性字段去关联统计。
环形缓冲区也是必练场景:某个设施周围500米到1000米之间的区域怎么求?实际做法是先做500米缓冲和1000米缓冲,再用Erase把内圈从外圈里去掉。这里给出一段可跑的代码:
# 道路中心线缓冲:先做整体合并缓冲,再做环状缓冲 from arcpy import env import arcpy env.workspace = r"D:\gis_work\ch3_8\analysis.gdb" arcpy.env.overwriteOutput = True # 第一圈:500米缓冲,所有道路的重叠缓冲合并成一个整体 buf_500 = arcpy.analysis.Buffer("road_centerline", "road_buf_500m", "500 Meters", "FULL", "ROUND", "ALL") # 第二圈:1000米缓冲,保留每条道路的独立缓冲对象 buf_1000 = arcpy.analysis.Buffer("road_centerline", "road_buf_1000m_keep", "1000 Meters", "FULL", "ROUND", "NONE") # 两层相减,得到500到1000米之间的环形区域 ring_500_1000 = arcpy.analysis.Erase(buf_1000, buf_500, "road_ring_500_1000")参数说明:Buffer的第三个参数是缓冲距离或距离字段,这里直接写带单位字符串“500 Meters”;第四个参数FULL表示在线要素两侧都生成缓冲区,如果只想保留左侧或右侧,可以写LEFT或RIGHT;第五个参数ROUND是端点处用圆头,说明练习里涉及道路、管线这类线要素时一般不会用到FLAT平头;第六个参数Dissolve已在上文说明。Erase是用buf_500作为擦除范围,从buf_1000中减去,注意两者的输入输出不能颠倒。
3.2 叠加分析:Intersect、Clip、Union 三选一
叠加分析是矢量空间分析的核心场景。很多练习数据在叠加这一步可能要连续跑几个图层,每次结果都是一个新的要素类。很多人不管三七二十一全部用Intersect,这其实不对。四类叠加工具各有适用的场景,选错会导致属性丢失或结果范围完全不同。
| 工具 | 输入 | 输出特征 | 典型用途 |
|---|---|---|---|
| Clip | 一个输入加一个裁剪要素 | 保留输入要素的属性和裁剪范围形状 | 把研究范围外的数据裁掉 |
| Intersect | 两个及以上要素类 | 只输出空间重叠部分,属性合并 | 找同时满足多个条件的区域 |
| Union | 两个及以上面要素 | 输出所有范围的并集,属性保留且带空值 | 做全区域的空间单元拆分 |
| Update | 两个要素 | 用更新要素替换原要素的几何 | 成果修正和边界替换 |
举个例子:要找出“既是现状建设用地,又位于洪水风险区内”的地块,用Intersect最合适,输出结果里同时保留两个图层的属性,你可以继续根据风险等级字段筛选用地。如果是要把整个研究区按地块、坡度分级、土地利用类型切分成若干个小单元,每个单元有各类属性,就用Union,但Union处理数据量大,字段嵌套后很容易出现几千个小碎面,需要权衡。
这里给出一段相交分析的代码:
# 叠加分析:找出同时满足两个条件的图斑 arcpy.analysis.Intersect(["landuse_2022", "flood_zone"], "lu_flood_inter", "ALL", "", "INPUT")参数说明:第一个参数输入要素类列表,可以放两个或更多图层;第二个是输出要素类;第三个JoinAttributes写成ALL,代表保留所有输入要素的属性字段;第五个Output_Type写成INPUT,表示输出几何类型与输入要素一致。还有一个隐蔽参数叫cluster_tolerance,如果两个图层边界存在微小缝隙,过大的容差值会把本来不相连的细碎边界咬合到一起,练习数据一般不特设,默认值即可。
叠加完成后,通常需要按属性筛选。比如两个图层相交后,字段risk_level等于高、且用地类型是居民地的记录才是真正需要的结果。接着补一步:
arcpy.analysis.Select("lu_flood_inter", "target_blocks", "landuse = '居民用地' AND risk = '高'")这段代码的作用是:从叠加结果里按 SQL 条件抽取目标图斑,避免直接删除原始结果。条件里字段名和取值都来自原始属性表,写错字段名不会报错,只会返回空,这种“空结果不报错”是练习数据阶段最需要警惕的情况,后面会专门讲排查。
3.3 叠加前先修复几何:三个小动作
练习数据从不同来源拼到一套资料里后,经常带有多余的重复顶点、自相交边界甚至空几何。直接拿这些要素类去叠加,轻则结果遗漏部分图斑,重则程序报错并且不告诉你哪条记录有问题。所以我每次都把“修复几何”放在叠加之前执行,这个动作在 ArcToolbox 里叫Repair Geometry,ArcPy 对应的是RepairGeometry_management。
# 叠加前必修:修复几何 + 剔除空值字段 arcpy.management.RepairGeometry("landuse_2022") arcpy.analysis.Select("landuse_2022", "landuse_valid", "shape_area > 0 AND objectid IS NOT NULL")这段代码的意图是:先修复所有错误几何,再把面积为0或空值的记录排除。练习数据中偶尔会有面积为0的点状退化为面或线,这类记录如果不处理,会在叠加或面积统计时产生 BUG。其次,输出路径尽量写到analysis.gdb里,不要用in_memory临时内存路径。内存路径速度快,但 ArcGIS 会话结束后数据会被清掉,而你第二次打开工程时可能已经不记得这个中间结果是怎么来的了。写到数据库里的中间成果,至少能保留一份可以回溯的痕迹,这在排查“为什么结果不一致”时价值极高。
4. 栅格计算与表面分析:像元大小、NoData、坡度坡向三处翻车点
4.1 做栅格计算前,先锁定 Extent、CellSize、Mask 三个环境变量
栅格计算看起来是输入两个栅格跑一个表达式,实际上它的结果受环境参数影响极大。最常见的例子是:DEM 像元大小是10米,土地利用栅格是30米,直接用栅格计算器做表达式,输出像元大小是哪个?不同版本默认逻辑不一样,多数情况下它会取输入中较大的像元,也就是30米。如果你没有意识到这一点,后续再用这个结果去统计面积,所有面积都会偏大或偏小。
在使用栅格计算、重分类、坡度分析之前,我把三个环境变量固定下来:snapRaster用于控制栅格像元对齐,extent用于控制输出范围,mask用于控制有效分析区域。这里的环境参数有点像“黑匣子”,你不知道它怎么工作的时候以为是玄学,看清楚之后就知道每一次栅格输出都受这些参数支配。
# 栅格计算前统一环境变量:像元、范围、掩膜 import arcpy from arcpy import env env.workspace = r"D:\gis_work\ch3_8\analysis.gdb" env.snapRaster = "dem_10m" # 对齐到DEM的像元网格 env.extent = "dem_10m" # 结果范围与DEM一致 env.mask = "study_area" # 只保留研究区内的像元 env.cellSize = 10 # 输出像元大小统一成10米参数说明:snapRaster是环境参数里最容易被忽略的一个。如果输入栅格和输出栅格的像元网格错开,重分类结果会在影像上出现半个像元的偏移,某些手工对比看不出来,但面积统计会差出好几行。extent可以设置为MAXOF或INTERSECTION,但最稳妥的方式是指定一个基准栅格,让所有输出都落在同一个范围;mask指定分析掩膜,掩膜外的像元会变成 NoData,这样后续统计就不会把研究区外的像元算进去。
还要记住一个 NoData 规则:栅格计算里,任何与 NoData 像元进行的数学运算,结果都是 NoData。这意味着,如果 DEM 里有几个无效空洞像素,你直接做DEM * 2,这些空洞不会变成0,而是保持 NoData 并传染到相邻计算结果中。所以当结果出现大面积空白时,不要先怀疑公式,先去检查输入栅格是否包含 NoData 区域。
4.2 重分类与条件计算:Con 和 Reclassify 的配合
栅格分析在练习数据里大量用于“符合条件区域提取”。比如高程大于50米、坡度小于15度、距离道路小于1000米的区域,这类多条件筛选最常用的工具是Con。Con的判定结果是布尔栅格,条件为真输出一个值,为假输出另一个值。它可以嵌套多个逻辑条件,也可以用&、|组合。
from arcpy.sa import * dem = Raster("dem") slope = Slope(dem, "DEGREE", 1) # 条件:坡度不大于15度,且高程大于50米,满足输出1,否则输出0 condition = (slope <= 15) & (dem > 50) result = Con(condition, 1, 0) # 保存结果 result.save("flat_area_mask") # 另一种方式:先重分类成等级,再做统计 dem_class = Reclassify(dem, RemapRange([[0, 50, 1], [50, 100, 2], [100, 5000, 3]]), "NODATA") dem_class.save("dem_class_3")这段代码的逻辑说明:先读取dem栅格,Slope计算坡度,condition是布尔栅格而不是文本条件,它只能在 Spatial Analyst 环境里被解释为栅格对象。Con第一参数是条件,第二参数是真值,第三是假值。Reclassify用于把连续高程分成三档,断点分别是50和100。这里边界的归属规则很容易把人绕晕:重分类默认认为下界包含、上界不包含,也就是高程正好等于50的像元会落到第二档而不是第一档。练习数据里如果正好卡在边界值,建议在重分类后用“属性表”检查像元数量,不要把边界值当成开区间处理。
重分类输出里的"NODATA"参数表示所有未在RemapRange中指定的值都变成 NoData。如果你希望未指定值变成0而不是 NoData,把这个参数改成0即可。两种写法会影响后续 Con 判定:NoData 在 Con 里仍然传播为 NoData,而值为0的像元会参与逻辑运算。
4.3 坡度坡向参数背后的换算关系
坡度工具的第一个关键是输出类型:DEGREE 是度数,PERCENT_RISE 是百分比。度数坡度和百分比坡度之间的对应不是线性的,45度等于100%坡度,30度只有57.7%。练习里经常要求用度数重分类出耕地适宜区或建设用地适宜区,如果你输出的是百分数,后面所有阈值都会错。
第二个关键是zFactor,即垂直比例因子。当 DEM 的水平坐标单位是米、高程单位也是米时,zFactor=1;当高程单位是英尺而水平坐标是米时,需要把高程转换系数设为0.3048。在 ArcGIS 默认的 Slope 工具对话框里,zFactor 默认为1,很多人不管数据直接跑,遇到起伏剧烈的假地形,实际就是 zFactor 用错了。
第三个关键是 DEM 噪声。如果原始 DEM 有测量噪声,直接算坡度会在局部出现极不合理的陡坡。常见做法是先做一个3x3均值滤波,再进行坡度坡向分析。滤波会损失一小部分细节,但它对坡度和坡向结果稳定性的提升非常明显。这里给出一段带滤波的代码:
from arcpy.sa import * dem = Raster("dem_10m") # 3x3均值邻域滤波,先压掉DEM里的孤立噪声像元 dem_smooth = FocalStatistics(dem, NbrRectangle(3, 3, "CELL"), "MEAN") # 度数坡度和百分比坡度 slope_deg = Slope(dem_smooth, "DEGREE", 1) slope_pct = Slope(dem_smooth, "PERCENT_RISE", 1) # 坡向:0为正北,顺时针方向;平坦区域输出-1 aspect = Aspect(dem_smooth) aspect = Con(aspect < 0, 0, aspect) # 把平坦区域的-1处理成0参数说明:FocalStatistics的第一个参数是输入栅格,第二个是邻域形态,这里用3x3矩形象元邻域,第三个是统计类型,MEAN表示均值。Slope的第三参数就是前述 zFactor,数据单位匹配时设为1。Aspect输出值域0到360度,0度代表正北,90度代表正东,但在平坦地区输出 -1,很多初学人员在使用坡向做朝向分类时忘记处理 -1,导致分类结果里多出一类“平地”。这里通过Con(aspect < 0, 0, aspect)把它归入0度,避免它干扰朝向统计。
5. 水文分析与网络分析:结果和教材对不上的五个排查方向(避坑)
5.1 水文分析流程与阈值调整
地形和水文分析是3-8章练习数据里最容易“镜像”的章节。DEM 数据经过填洼、流向、汇流累积量、河网提取、流域划分整整一串工具,中间任何一步参数变一点,后面结果就完全不一样。水文分析最常用的流向算法是 D8,也就是每个像元选择一个最陡的下坡方向,把水流方向定义为八方向之一。这个算法在上游山地区域表现良好,但在平坦地区或人工整平区域会出现大量“平行线”水流,这是算法特性,不是你的操作问题。
先跑一个最小流程:
from arcpy.sa import * dem = Raster("dem_10m") # 填洼:z_limit 单位和高程一致,不建议直接放默认无限制 dem_fill = Fill(dem, z_limit=10) # 流向计算:平缓区域多时,可以用"流向"工具的默认D8算法 flow_dir = FlowDirection(dem_fill, force_flow="NORMAL") # 汇流累积量 flow_acc = FlowAccumulation(flow_dir) # 用阈值1000提取河网,结果看断线情况再调整 stream_grid = Con(flow_acc > 1000, 1) stream_line = StreamToFeature(stream_grid, flow_dir, "stream_line")参数说明:Fill的z_limit=10表示只填平高度差不超过10米的洼地,超过10米的低洼保持原状。这个参数非常关键,如果设为 None,工具会把所有洼地填到与最低出水口齐平,结果是大量地形被削平,流向图出现大面积平坦区。FlowDirection的第二参数force_flow设为NORMAL,表示边缘像元不强制向外流出;如果设为FORCE,边界像元全部指向区域外,河网会在边界出现人为直线。Con(flow_acc > 1000, 1)是把汇流累积量大于1000的像元标为河道。阈值不是教材固定值,它取决于DEM分辨率与区域规模,10米DEM在丘陵区用1000可能合理,在平原区可能要降到200,要结合影像或参考水系反复试。
5.2 网络分析的数据准备与两个惯用操作
网络分析在练习数据里主要是最佳路径、服务区和最近设施三种场景。很多人第一次做网络分析,点了求解按钮却提示“无法求解”,第一反应是工具问题,实际上大概率是网络数据集没有构建,或者道路线没有在路口处打断。ArcGIS 里必须把道路要素类构建成网络数据集,系统才知道从哪里转弯、哪条路和哪条路连通。
常用的构建流程是:先检查道路数据是否已经有交通网络属性,也就是速度、单行道、等级这些字段;然后在目录里右键道路要素类,选择“构建网络数据集”,设置连接策略,对普通城市道路一般用“端点连接”,保证两条路只有在端点相交时才连通;最后执行构建。如果修改了道路几何或属性,必须重新构建,否则网络数据集中保存的还是旧数据。
# 构建网络数据集:roads_ND 是事先建立好的网络数据集名称 arcpy.na.BuildNetwork("roads_ND")这段代码只做一件事:根据当前道路源数据重新构建网络数据集。构建网络数据集之前,要确保道路要素没有悬挂的大段未打断线段。练习数据如果是从CAD转换来的道路,经常出现十字路口两条线只是视觉交叉、实际没有公共端点的情况,这种道路网无论如何都解算不出跨路口的路径。处理方式是在 Pro 的“编辑”模式下选中有关道路,使用“打断相交线”工具,把所有交点处打断;或者在地理数据库拓扑里加一条“不能有悬挂点”的规则。这部分内容偏数据处理,不是网络分析本身的问题,但却是网络分析最经常翻车的环节。
5.3 现象 → 原因 → 解决的五个排查记录
水文和网络分析课程里,几乎所有人都会在同一个地方反复失败。这里整理五条最典型的踩坑记录,按现象、原因、解决的顺序说明,练习时可以直接对照排查。
第一,填洼后地形变成大片平地。现象:执行 Fill 后,DEM 视图里大面积区域变成同一个颜色,流向图出现成排的直线或平行线。原因:z_limit 参数被设为 None 或值设置得过大,系统把真实的山间低洼和 DEM 边界错误全部填平。解决:填洼前先读取 DEM 的 min 和 max,把 z_limit 设为一个相对小的高差,例如5到15米,针对丘陵区可以从10开始试;填洼后用“识别”工具查看平坦区域高程是否接近原 DEM 最低值,如果完全一样,说明填洼过度。
第二,河网提取出来是断断断续续的短线。现象:Con 提取的河网上游缺失、中游断线,或者提取结果和影像上的水系对不上。原因:汇流阈值过高,或者原始 DEM 没有填洼,凹陷区域中断了流向。解决:把提取阈值从1000降到300或200重新跑;回到 Fill 步骤检查 z_limit;也可以在提取前对 flow_acc 做一次低通滤波。河网矢量化后,用“河流分级”工具按 Strahler 分级过滤掉一级短小分支,画面会干净很多。
第三,网络分析解算路径绕大圈或提示无法到达。现象:求解最佳路径时,明明两个点在图上相邻,结果路径绕到几公里外。原因:道路网络连通性差,路口处线未打断,或者两个点没有正确捕捉到网络上。解决:先检查路网源数据在路口处是否已打断,使用“打断相交线”后重建网络数据集;再检查停靠点是否有捕捉设置,练习数据里点位距离道路几十米时,求解器可能捕捉到错误的道路段,最好用“捕捉”工具把点移动到最近的路上再求解。
第四,面积或距离结果量级差到十万八千里。现象:缓冲区结果范围大得离谱,或者面积统计值在0.0001附近波动。原因:图层还是地理坐标系,Buffer 单位被人为解释为度,面积工具在度坐标系下给出的是平方度而不是平方米。解决:打开图层属性查看坐标系,如果是 GCS_WGS_1984,先投影到本地高斯投影或 UTM,再执行缓冲和面积统计;在编写代码时,在所有距离参数里显式带上单位,例如“500 Meters”,不要只写500。
第五,叠加分析结果出现大量细碎小多边形。现象:Intersect 或 Union 结果里有一屏幕的长条细碎图斑,面积很小,边界沿着两个输入图层的边缘走。原因:两个输入图层的边界不完全重合,空间容差设置太大或太小,导致微缝被识别为独立多边形。解决:叠加前对两个输入做 Repair Geometry;在叠加工具的高级参数里检查 Cluster Tolerance,默认值通常是数据精度合适的结果;细碎图斑产生后,按面积阈值筛选,把小于研究区最小制图单元的多边形删掉或合并到邻接要素。
6. 用交叉验证给练习结果打分:空间分析的最后一道工序
做完插值、叠加、流域提取之后,很多人看到结果图就直接写报告了,但我建议你养成一个习惯:给分析结果做一个验证。尤其是插值分析,比如练习数据里用采样点生成降雨、土壤元素含量或人口密度表面,颜色渐变再好看,也不能证明它可靠。插值工具在 ArcGIS 里默认会生成预测表面,但不会主动告诉你这个表面的误差是多少,而“交叉验证”就是把这个误差显式算出来。
做法并不复杂:把原始实测点按20%左右的比例抽出一部分作为验证点,不要把验证点参与插值;用剩下的80%样本点生成预测表面;然后在验证点位置提取预测值,对比实测值和预测值,计算平均误差和均方根误差 RMSE。如果平均误差接近0,说明没有系统性高估或低估;RMSE 越小,说明预测表面和实测点越吻合。练习数据里如果只有一份插值结果而没有验证点,也可以用“GA Layer To Points”工具提取每个采样点处的预测值,对全部样本做交叉验证。
| 指标 | 计算公式 | 说明 |
|---|---|---|
| 平均误差 Bias | 预测减实测的平均值 | 接近0说明无系统性偏差 |
| 均方根误差 RMSE | 预测减实测的平方均值再开方 | 量纲与原始数据一致,越小越好 |
| 标准化 RMSE | RMSE 除以实测标准差 | 小于1说明插值优于直接用均值估计 |
在实际操作中,我会在验证点图层属性表里保留两个字段:实测值字段和预测值字段,然后导出为 CSV,用一小段 Python 计算误差指标:
import csv, math # 从验证点属性表导出 CSV,字段名分别为 pred 和 observed rows = [] with open("validation_points.csv", encoding="utf-8") as f: for rec in csv.DictReader(f): if rec["pred"] and rec["observed"]: rows.append((float(rec["pred"]), float(rec["observed"]))) n = len(rows) bias = sum(p - o for p, o in rows) / n rmse = math.sqrt(sum((p - o) ** 2 for p, o in rows) / n) print(f"样本数={n}, 平均误差={bias:.3f}, RMSE={rmse:.3f}")这段代码的逻辑很简单:读取每一行,剔除缺失值,计算平均误差和均方根误差。它不依赖任何 ArcGIS 接口,导出 CSV 后可以直接用于报告,也可以作为一次基准记录下来。交叉验证的真正价值不是得到一个好看数字,而是让你在换参数、换插值方法时,有一个可以比较的指标。练习数据阶段,你可以用同一份数据分别跑普通克里金和反距离加权,最后对比 RMSE,哪个小选哪个,这比盯着图层颜色判断靠谱得多。
我现在的习惯是拿到任何一批新数据,都先按《ArcGIS空间分析实例与练习数据3-8章》里的思路把环境参数锁死,再按步骤跑,跑完必然看精度报告而不是只看地图。以前在某次测数据时,我照着教材阈值直接跑河网,结果下游流域面积差出三倍,最后定位到是填洼 z_limit 开得太大,把真实山脊都削平了。那次之后,我给自己定了一条规矩:原始数据不动、每一步输出留名、结果必须验证。练习数据的意义就在于此,数据可以换,流程和校验习惯不能丢。希望帮到你。
本文还有配套的精品资源,点击获取