ArcPy解析:安然产品有治痘痘的吗?GIS空间分析(附数据)

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

《ArcPy解析:安然产品有治痘痘的吗?GIS空间分析(附数据)》这篇文章不讨论产品功效,也不做医疗或消费建议,而是把这个看似“非典型 GIS 问题”转化为一个可复现的空间分析练习:如何用 ArcPy 对门店点位、用户咨询点、行政区和缓冲区数据进行整理、叠加、统计与制图输出。

引言:把一个搜索问题转成 ArcPy 空间分析任务

很多 GIS 初学者会遇到类似问题:手里有一批门店、用户咨询、投诉记录、销售网点或采样点数据,想知道它们在空间上是否集中、覆盖哪些区域、距离目标人群或服务点有多远。标题中的“安然产品有治痘痘的吗”本身属于产品与健康咨询问题,不能用 GIS 直接判断产品是否有效。

但 GIS 可以回答另一类更明确的问题:

  • 相关门店或咨询点在城市中如何分布?
  • 哪些行政区咨询记录更多?
  • 用户点位距离最近门店有多远?
  • 500 米、1 公里、3 公里服务范围能覆盖多少咨询点?
  • 如果要做线下调研,哪些区域应优先抽样?

本文以 ArcPy 解析空间数据为主线,演示一个完整流程:数据准备、坐标系统一、缓冲区分析、空间连接、最近距离计算、分区统计和结果导出。读者可以把示例数据替换成自己的门店 POI、问卷点、病例匿名化点位、咨询记录或市场调研点。

ArcPy解析空间分析与ArcPy缓冲区分析流程示意图
ArcPy 空间分析流程:从点位数据清洗到缓冲区、空间连接和统计结果输出。

背景:这个问题为什么适合做空间分析练习

“某类产品是否有效”属于医学、监管和实验验证问题,GIS 不能替代临床证据。但如果问题被拆解为“相关咨询、销售、门店、服务覆盖和空间分布”,就可以用 ArcPy 做客观的数据分析。

在实际项目中,类似场景非常常见:

  • 零售门店选址:分析用户咨询点与门店距离。
  • 公共服务覆盖:分析服务点 1 公里范围内覆盖多少居民点。
  • 投诉热点识别:统计投诉点在各街道或社区中的数量。
  • 市场调研布点:寻找咨询密集但门店不足的区域。
  • 健康 GIS 研究:在合规匿名化前提下分析空间分布,而不是判断个体疗效。

因此,本文重点不是评价某个产品,而是演示如何用 ArcPy 解析点位数据并完成 GIS 空间分析。这个流程对 ArcGIS Pro 用户、ArcPy 初学者和空间数据分析人员都很实用。

原理:ArcPy 空间分析要先弄清三个核心对象

1. 点、面和属性表

本案例中可以把数据抽象成三类:

  • 咨询点或用户点:通常来自 CSV、Excel、问卷系统或数据库,包含经纬度字段。
  • 门店点或服务点:表示线下网点、服务站、采样点或销售点。
  • 行政区面:例如区县、街道、社区边界,用于做分区统计。

ArcPy 的空间分析本质上是在几何对象和属性表之间建立关系。例如,一个咨询点落在哪个街道内,距离最近门店多远,是否在某个缓冲区范围内。

2. 坐标系决定距离和面积是否可信

ArcPy 解析空间数据时,最容易出错的是坐标系。经纬度坐标通常使用 WGS 84 或 CGCS2000 地理坐标系,单位是度;而距离分析、缓冲区分析通常需要投影坐标系,单位是米。

如果直接在经纬度坐标上做 1000 米缓冲区,很可能得到错误结果。因此,本教程会先检查坐标系,再投影到适合本地分析的投影坐标系。

3. 空间连接与近邻分析的区别

空间连接用于回答“这个点落在哪个面内”或“这个面内有多少点”。

近邻分析用于回答“每个咨询点距离最近门店有多远”。

缓冲区分析用于回答“门店周边 1 公里范围内覆盖了哪些咨询点”。

这三类工具经常一起使用,是 ArcPy 空间分析中最基础、最常用的一组方法。

步骤:用 ArcPy 完成点位解析、缓冲区和统计

步骤 1:准备示例数据字段

假设我们有三份数据:

数据 格式 关键字段 用途
consult_points.csv CSV id、lon、lat、question_type 用户咨询点或调研点
stores.csv CSV store_id、lon、lat、store_name 门店或服务点
districts.shp Shapefile district_id、district_name 行政区统计边界

注意:经纬度字段必须是数值型,不要带中文逗号、空格、单位或异常字符。若来自 Excel,建议先另存为 UTF-8 CSV。

步骤 2:建立 ArcPy 工作空间

import arcpy
import os

arcpy.env.overwriteOutput = True

project_folder = r"D:gisyxsarcpy_product_analysis"
gdb = os.path.join(project_folder, "analysis.gdb")

if not arcpy.Exists(gdb):
    arcpy.management.CreateFileGDB(project_folder, "analysis.gdb")

arcpy.env.workspace = gdb

consult_csv = os.path.join(project_folder, "data", "consult_points.csv")
stores_csv = os.path.join(project_folder, "data", "stores.csv")
districts = os.path.join(project_folder, "data", "districts.shp")

建议使用 File Geodatabase 作为中间工作空间,而不是一直使用 Shapefile。原因是 Shapefile 字段名长度有限,中文字段和编码也更容易出问题。

步骤 3:把 CSV 转成点要素

wgs84 = arcpy.SpatialReference(4326)

consult_points = os.path.join(gdb, "consult_points_wgs84")
stores_points = os.path.join(gdb, "stores_wgs84")

arcpy.management.XYTableToPoint(
    in_table=consult_csv,
    out_feature_class=consult_points,
    x_field="lon",
    y_field="lat",
    coordinate_system=wgs84
)

arcpy.management.XYTableToPoint(
    in_table=stores_csv,
    out_feature_class=stores_points,
    x_field="lon",
    y_field="lat",
    coordinate_system=wgs84
)

如果输出点位全部跑到海上、国外或地图左下角,通常是经纬度字段填反、坐标系指定错误,或者原始数据不是 WGS 84。

步骤 4:投影到米制坐标系

距离和缓冲区分析建议使用投影坐标系。这里以 Web Mercator 作为演示,但正式项目中更推荐选择本地高斯克吕格、UTM 或当地测绘部门规定的投影坐标系。

projected_sr = arcpy.SpatialReference(3857)

consult_prj = os.path.join(gdb, "consult_points_prj")
stores_prj = os.path.join(gdb, "stores_prj")
districts_prj = os.path.join(gdb, "districts_prj")

arcpy.management.Project(consult_points, consult_prj, projected_sr)
arcpy.management.Project(stores_points, stores_prj, projected_sr)
arcpy.management.Project(districts, districts_prj, projected_sr)

如果研究区较小,Web Mercator 的误差在教学演示中可以接受;如果要做正式报告,必须使用适合研究区的投影坐标系,并在报告中说明坐标系来源。

步骤 5:生成门店 1 公里缓冲区

store_buffer_1km = os.path.join(gdb, "store_buffer_1km")

arcpy.analysis.Buffer(
    in_features=stores_prj,
    out_feature_class=store_buffer_1km,
    buffer_distance_or_field="1000 Meters",
    dissolve_option="ALL"
)

这里使用 dissolve_option=”ALL”,表示把所有门店的 1 公里服务范围合并成一个整体。如果你想分别统计每个门店覆盖的咨询点,应改为不融合,或按门店 ID 融合。

步骤 6:筛选落在缓冲区内的咨询点

consult_in_buffer = os.path.join(gdb, "consult_in_store_1km")

arcpy.analysis.SpatialJoin(
    target_features=consult_prj,
    join_features=store_buffer_1km,
    out_feature_class=consult_in_buffer,
    join_operation="JOIN_ONE_TO_ONE",
    join_type="KEEP_COMMON",
    match_option="INTERSECT"
)

这一步可以得到“门店 1 公里范围内的咨询点”。如果你要计算覆盖率,可以用缓冲区内点数除以总咨询点数。

total_count = int(arcpy.management.GetCount(consult_prj)[0])
covered_count = int(arcpy.management.GetCount(consult_in_buffer)[0])

coverage_rate = covered_count / total_count if total_count else 0

print("咨询点总数:", total_count)
print("1公里覆盖点数:", covered_count)
print("覆盖率:", round(coverage_rate * 100, 2), "%")

步骤 7:计算每个咨询点到最近门店距离

near_table = os.path.join(gdb, "consult_nearest_store")

arcpy.analysis.GenerateNearTable(
    in_features=consult_prj,
    near_features=stores_prj,
    out_table=near_table,
    search_radius="",
    location="NO_LOCATION",
    angle="NO_ANGLE",
    closest="CLOSEST",
    closest_count=1,
    method="PLANAR"
)

GenerateNearTable 会生成一个近邻表,包含 IN_FID、NEAR_FID 和 NEAR_DIST 等字段。NEAR_DIST 的单位取决于输入数据的投影坐标系,本例中可按米理解。

如果你发现 NEAR_DIST 数值特别小或特别大,优先检查投影坐标系是否正确。

步骤 8:按行政区统计咨询点数量

consult_with_district = os.path.join(gdb, "consult_with_district")

arcpy.analysis.SpatialJoin(
    target_features=districts_prj,
    join_features=consult_prj,
    out_feature_class=consult_with_district,
    join_operation="JOIN_ONE_TO_ONE",
    join_type="KEEP_ALL",
    match_option="CONTAINS"
)

输出结果中的 Join_Count 字段通常表示每个行政区内连接到的点数量。你可以用它识别咨询记录较多的区域。

步骤 9:导出统计表

output_table = os.path.join(project_folder, "output", "district_consult_count.csv")

arcpy.conversion.TableToTable(
    in_rows=consult_with_district,
    out_path=os.path.dirname(output_table),
    out_name=os.path.basename(output_table)
)

导出 CSV 后,可以继续在 Excel、Power BI、Python pandas 或 ArcGIS Pro 中制作图表。对于 GIS 初学者来说,先把 ArcPy 分析结果落到表格,是检查结果是否合理的好办法。

常见坑:ArcPy解析空间数据时最容易错在哪里

1. 把经纬度直接拿来做距离分析

经纬度的单位是度,不是米。ArcPy 缓冲区分析和近邻分析如果使用地理坐标系,很容易产生不可信的距离结果。解决办法是先投影到合适的米制坐标系。

2. lon 和 lat 字段写反

中国范围内常见经度大约在 73 到 135,纬度大约在 18 到 54。如果 lon 字段值是 30,lat 字段值是 120,大概率是经纬度反了。

3. CSV 编码导致中文字段乱码

ArcPy 读取 CSV 时,中文字段名、中文路径和特殊符号可能引发问题。建议使用英文路径、英文字段名,并把 CSV 保存为 UTF-8 编码。

4. Shapefile 字段名被截断

Shapefile 字段名最长通常只有 10 个字符,容易把 district_name 截断成 district_n。建议中间数据统一放入 File Geodatabase。

5. 忽略数据合规和隐私

如果咨询点、用户点或健康相关数据来自真实业务,必须先做脱敏、聚合或匿名化处理。不要在地图上公开展示个人地址、手机号、姓名或可识别个人身份的信息。

方法比较:缓冲区、空间连接和近邻分析怎么选

分析方法 适合回答的问题 ArcPy 常用工具 注意事项
缓冲区分析 门店周边 1 公里覆盖哪些点 Buffer 必须使用合理投影坐标系
空间连接 每个行政区有多少咨询点 SpatialJoin 注意 CONTAINS、INTERSECT 等匹配关系
近邻分析 每个点到最近门店多远 GenerateNearTable、Near 检查距离单位和搜索半径
热点分析 是否存在统计意义上的高值聚集 HotSpots、OptimizedHotSpotAnalysis 需要足够样本量和合适空间尺度
核密度分析 点位密集区在哪里 KernelDensity 结果受搜索半径和像元大小影响明显

如果只是做入门级 ArcPy 解析,建议先掌握缓冲区、空间连接和近邻分析。它们逻辑清楚、结果容易检查,也最适合写入自动化脚本。

检查清单:运行脚本前后逐项核对

运行前检查

  • CSV 路径是否为英文路径或无特殊字符路径。
  • lon、lat 字段是否存在,且为数值型。
  • 经纬度是否没有填反。
  • 点数据和行政区数据是否在同一城市或同一研究区。
  • 是否明确原始坐标系,例如 WGS 84、CGCS2000 或地方坐标系。
  • 是否已经准备 File Geodatabase 作为输出工作空间。

运行后检查

  • 点位是否落在正确城市。
  • 缓冲区半径是否符合预期。
  • 空间连接结果中 Join_Count 是否异常为 0。
  • NEAR_DIST 距离是否符合常识。
  • 导出表是否字段完整、编码正常。
  • 是否避免公开敏感个人信息。

经验建议:不要只看脚本是否运行成功,还要把关键中间结果加载到 ArcGIS Pro 地图中检查。空间分析最怕“程序没报错,但结果是错的”。

FAQ:ArcPy解析与空间分析常见问题

Q1:ArcPy 能判断“安然产品有治痘痘的吗”吗?

不能。ArcPy 和 GIS 空间分析不能判断产品疗效,也不能替代医学证据。本文的重点是把相关咨询点、门店点或调研点作为空间数据,分析其分布、覆盖范围和距离关系。

Q2:ArcPy缓冲区分析为什么一定要注意坐标系?

因为缓冲区半径通常以米为单位,而经纬度坐标的单位是度。如果坐标系不合适,1000 米缓冲区可能并不是真正的 1000 米。正式分析应使用适合研究区的投影坐标系。

Q3:空间连接结果 Join_Count 全是 0 怎么办?

优先检查三件事:点和面是否在同一位置,坐标系是否一致,match_option 是否选择正确。如果行政区面没有包含点,可以尝试 INTERSECT,并在地图中查看点是否真的落入面内。

Q4:GenerateNearTable 和 Near 工具有什么区别?

Near 工具通常会把最近距离字段直接写回输入要素;GenerateNearTable 会生成独立近邻表,更适合保留多条近邻关系或后续表连接。教学和批处理场景中,GenerateNearTable 更便于检查。

Q5:没有 ArcGIS Pro 可以运行 ArcPy 吗?

通常需要安装 ArcGIS Pro,并使用其自带的 Python 环境运行 ArcPy。ArcPy 不是普通 pip 包,不能像 pandas 一样直接在任意 Python 环境中安装。

Q6:如果数据量很大,ArcPy 空间分析会很慢吗?

会。点位数量较大时,应优先使用 File Geodatabase,建立空间索引,减少不必要字段,并按研究区分块处理。对于数据库级空间分析,也可以考虑 PostGIS。

结论:用 ArcPy 解决清楚的问题,而不是替代专业判断

本文围绕“ArcPy解析:安然产品有治痘痘的吗?GIS空间分析(附数据)”这个标题,给出了一个更适合 GIS 读者的实践角度:不评价产品功效,而是用 ArcPy 分析咨询点、门店点和行政区之间的空间关系。

完整流程包括 CSV 转点、坐标系统一、ArcPy缓冲区分析、空间连接、最近距离计算和统计表导出。只要替换输入数据,读者就可以把这套方法用于门店覆盖、服务半径、投诉分布、调研抽样和公共服务可达性分析。

最后记住三点:第一,医学或产品功效问题不能由 GIS 直接证明;第二,距离和缓冲区分析必须重视坐标系;第三,ArcPy 脚本运行成功不等于分析结果正确,必须在地图和表格中做交叉检查。