章节概述
本章聚焦空间数据中的点要素 (Point Data),以专题研究为主线,结合真实的多源城市数据展开分析。
专题研究 1 以曼哈顿 Airbnb 房源数据为例,讨论价格的空间异质性与集聚特征;专题研究 2 以上海闵行区的微博地理坐标点与公共交通 POI为例,识别数字活动热点并分析交通可达性差异。
方法层面,本章主要涉及六边形聚合、空间自相关 (Moran’s I / LISA)、核密度估计 (KDE)、AOI 提取,以及在章节练习中引入的DBSCAN聚类,用于理解点模式的空间结构。
本章学习内容
欢迎开始 第 5 章 的学习。请点击 下方导航卡 进入相应小节:
点数据导论
研究框架
专题研究 1
实战案例与流程
总结与反思
专题研究 1
专题研究 2
多源点数据分析
总结与反思
专题研究 2
章节练习
复现与挑战
💡 提示:学习完一个小节后,请再次点击 屏幕右下角的章节主页按钮回到本导航页
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
基本概念
承接第四章的核心概念:在 sf
框架下,矢量空间数据本质上是“普通属性表 +
几何列(geometry)”的结合体。
作为最基础的空间几何形态,点(Point) 是零维对象,仅由一对坐标(如经纬度或投影 X/Y)唯一标识,无长度、面积与边界。然而,正是这种“极简”的物理形态,使其在计算社会科学与城市分析中极具应用价值。这些零维坐标背后,往往高度浓缩了真实的微观实体特征。
尺度延展性 (Scalability)
点具有极强的空间抽象能力。在微观尺度,它可精确至一个行人的驻留位置或一盏路灯;在中观尺度,它可抽象为居民小区或统计单元轮廓的重心;而在宏观网络中,它甚至能代表一座城市或国家。
属性挂载与空间集聚 (Attributes & Clustering)
点数据兼具高维信息承载力与群体分布特征。在个体属性上,以地铁站为例,单个几何点可同时挂载站名等静态信息与逐时客流等动态时序数据;在群体形态上,以社交媒体打卡为例,海量散点的相对位置分布与集聚形态,能直观映射出城市真实的活力热区与活动图景。
相较于面数据(如行政区、普查单元),点数据能以最高精度保留个体或事件的真实位置。该特性使其天然免疫区域统计中的可变面元问题(MAUP,请自行搜索相关概念),进而穿透人为划定的边界,在最微观尺度直接捕捉空间异质性与分布规律。
Figure 5.1. MAUP概念图
科研伦理与隐私
点数据的超高分辨率也伴随着严峻的数据伦理与隐私风险。代表物理设施(如建筑、餐厅 POI)的点数据通常开源可得;但涉及自然人个体位置(Personalised Data,如手机轨迹、私人住址)的高精度数据则极易侵犯隐私,获取门槛极高。
因此,在计算社会科学实践中,个体级敏感点数据常处于“受严格限制”状态。研究者在分析与发布此类数据时,必须严格执行空间脱敏、坐标模糊化(Jittering)或匿名聚合,在追求分析精度的同时坚守科研伦理底线。
在计算社会科学与城市分析中,点数据的来源极其广泛。根据其代表的物理形态与社会含义,大致可以将其系统划分为以下四类高频图谱。了解这些数据的特征与获取渠道,是进行空间统计分析的第一步。
常用
兴趣点(Point of Interest, POI) 是城市空间分析中最为基础的点数据类型。它不仅用于标识静止的物理设施或建成环境的具体地理位置,在计算社会科学中,更是承载人类活动、数字足迹与社会经济信息的空间锚点(Spatial Anchors)。
osmdata 包直接提取 OpenStreetMap (OSM)
的矢量要素;商业高精度数据多通过调用高德、百度或 Google Places API
获取。此外,各国与地方政府的开放数据平台亦提供极具权威性的官方
POI 库,例如英国的 Ordnance Survey (OS) 开放数据与美国纽约的 NYC
OpenData。Figure 5.2. POI数据概念图
常用
行为与事件记录是极具动态特征的点数据。它不仅拥有精确的空间坐标,还绑定了明确的时间戳(Timestamp)。这类数据将零维的静态空间点拓展为动态的时空切片 ,精准刻画了在特定地理坐标下瞬时发生的人类活动或城市突发事件。
Figure 5.3. 行为与事件类点数据概念图
常用
移动对象在地理空间中的连续运动形成了数字足迹(Digital Footprints)。根据时空采样率与记录机制的不同,此类数据主要表现为轨迹采样点与起讫点两个分析颗粒度:
轨迹采样点:
将连续的真实轨迹离散化为一系列高频时空采样点(Spatiotemporal Sampling Points,如按 30 秒或 1
分钟固定频率持续上传的空间坐标)。此类数据不仅记录了静态的位置,更精准还原了动态的空间过程。
起讫点(OD 点):
由起点(Origin)与终点(Destination)构成。其来源既可以是连续轨迹的空间简化(隐去中间路径以严格保护个人隐私),也常源于具有固定站点的系统记录(如公交地铁的进出站刷卡数据
Tap-in/Tap-out、有桩共享单车的借还记录)。OD
点抛弃了复杂的运动过程,构成了刻画城市内部与区域间流动的复杂网络连边(网络与流数据将于下一章详细展开)。
典型代表:
涵盖机动车(如出租车、物流车)与无桩微出行工具(如无桩共享单车)的连续 GPS
轨迹点;智能交通系统的离散节点记录(如出租车上下客点、有桩单车站点、地铁闸机);以及个体层面的手机信令驻留点或可穿戴设备记录。
算法衍生:演化处理
原始的高频轨迹常需经过空间算法计算(如驻留识别,Stop
Detection),提取为具有明确地理与社会语义的停留点(Stop
Points),或用于构建刻画个体日常活动范围的活动空间(Activity Space)模型。
科研方向与应用:
广泛应用于刻画城市流动性(Urban
Mobility)、测度职住空间分离与跨区域通勤效率、识别微观活动节律。在交通地理学与规划领域,常用于路网承载力评估、拥堵模式挖掘及低碳出行行为建模。
常见获取渠道:
少数标准微观数据源自交通管理部门的脱敏开放数据集(如纽约 TLC 出租车记录、Citibike
有桩单车数据)。
连续轨迹与微观个体 OD 极易暴露用户敏感住址与习惯,面临极高的隐私合规壁垒。在多数场景下,精细轨迹极难通过公开渠道获取,常需依托政府部门或互联网出行平台(如滴滴、美团、哈啰出行等)的深度合作。因此,目前开源且最广泛使用的形式多为聚合型 OD 数据(Aggregated OD Data,如汇总特定时段内某两地间的流量总数),在满足分析需求的同时规避了伦理风险。
Figure 5.4. 轨迹采样点与OD点数据概念图
常用
在宏观空间分析中,点数据往往并非直接采集的物理坐标,而是由高维空间要素(如行政区多边形、路网线段)通过几何或统计运算降维抽象而来的代表性节点。
sf::st_centroid()
等空间处理函数实时生成。降维陷阱与几何错位:在提取衍生点时,需警惕复杂几何特征带来的分析谬误。
对于形状极度不规则、带有巨大孔洞或呈“U/C型”弯曲的多边形(如环湖行政区、狭长海岸线城市),其几何重心极大概率会落在多边形的物理边界之外(参考第四章内容)。实战中,常需改用拓扑安全的sf::st_point_on_surface()函数或计算人口加权质心,以确保抽象出的节点符合真实的物理常识。
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
空间点数据探索性分析 (ESDA) 工作流
“从微观散点到宏观空间结构”
本节以曼哈顿 Airbnb 房源数据为例,介绍空间点数据探索性分析的基本流程,包括空间裁取与预处理、六边形聚合以及空间自相关分析。
点击下方卡片,快速跳转至相应模块:
课题与目标
ESDA 核心框架
区域与数据
曼哈顿边界提取
预处理映射
极值截断与渲染
网格化降维
六边形聚合重构
全局自相关
Moran’s I 检验
局部自相关
LISA 聚类探测
💡 提示:学习完一个小节后,请再次点击 屏幕右下角的专题导航按钮回到本导航页
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
重要 · 实战教学
本节以美国纽约市(NYC)的 Airbnb 点数据为例,通过真实案例进行空间点数据的基础处理与分析流程的教学。依托第三方独立开源项目(Inside Airbnb)提供的微观短租房源数据,本节聚焦曼哈顿(Manhattan)核心区,构建一套规范的探索性空间数据分析(ESDA, Exploratory Spatial Data Analysis)工作流。
示例课题
研究课题:
曼哈顿短租市场的空间分布与租金异质性分析:基于网格化降维与空间自相关模型
研究背景与目标:
在微观城市经济学与空间分析中,短租房源(如
Airbnb)的空间分布与定价策略是刻画城市商业活力与街区绅士化(Gentrification)进程的重要切入点。
本节依托第三方独立开源项目(Inside Airbnb)提供的纽约市微观短租房源数据,聚焦全球金融中心纽约市的核心曼哈顿(Manhattan)区,实现以下空间分析目标:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
第四章 6.0 小节已简要介绍了 Inside Airbnb 数据库,并基于英国伦敦的房源数据进行了实操。本节将聚焦美国纽约市(New York City)曼哈顿区的最新短租数据开展空间探索与分析。
纽约市位于美国大西洋沿岸,是世界最早的超大城市(Megacity,其都会区人口于 20 世纪 30 年代率先突破千万)之一。该市由五个行政区(Boroughs)组成,分别为曼哈顿(Manhattan)、布鲁克林(Brooklyn)、皇后区(Queens)、布朗克斯(The Bronx)以及斯塔滕岛(Staten Island)。本节的空间点模式分析将主要聚焦于其核心区域——曼哈顿。
数据获取
本阶段的任务是获取本研究所需的两个核心数据:曼哈顿行政边界 与 Airbnb 房源原始数据。
代码逻辑解析:
Step 1
曼哈顿主岛边界的提取与筛选(研究范围界定)
首先,代码对接了纽约市官方的
ArcGIS Feature
Service。由于原始数据包含纽约全境,通过逻辑筛选仅保留“曼哈顿”区域。关键步骤在于几何清洗:曼哈顿行政区实际上包含许多离散的小岛(如罗斯福岛、总督岛等),代码通过计算面积并降序排列,提取出面积最大的曼哈顿主岛作为后续分析的空间边界。
Step 2
地理语境下的空间验证(可视化校验)
在处理地理数据时,视觉验证是确保分析可靠性的必要环节。通过
ggspatial 插件叠加了轻量化的 CartoDB
底图,并将提取出的边界渲染在其上。
Step 3 Airbnb
原始房源数据的流式摄取(数据下载与读取)
本研究另一个数据来源于开源项目 Inside
Airbnb。代码直接访问其服务器上的 .csv.gz
压缩文件流。这种做法无需手动下载文件,可以直接获取包含房源地理坐标、价格梯度及经营属性的原始数据集。
# ============================================================
# 1. 依赖库加载与地理信息环境配置
# ============================================================
library(tidyverse)
library(sf)
library(ggspatial)
# ============================================================
# 2. 研究区域界定:曼哈顿海岸线边界提取与几何拓扑清洗
# ============================================================
# 2.1 访问纽约市官方边界要素服务 (ArcGIS REST API)
nyc_official_url <- "https://services5.arcgis.com/GfwWNkhOj9bNBqoJ/arcgis/rest/services/NYC_Borough_Boundary/FeatureServer/0/query?where=1=1&outFields=*&outSR=4326&f=pgeojson"
# 2.2 空间边界获取、有效性校验与主岛几何筛选
manhattan_boundary <- read_sf(nyc_official_url) %>%
# 筛选目标行政单元:曼哈顿区
filter(BoroName == "Manhattan") %>%
# 执行拓扑有效性修复,确保几何计算准确
st_make_valid() %>%
# 将多面体要素拆解为单体多边形,以识别并分离行政飞地
st_cast("MULTIPOLYGON") %>%
st_cast("POLYGON") %>%
# 几何计算:基于投影面积降序排列,精准提取面积最大的主岛实体
mutate(poly_area = as.numeric(st_area(.))) %>%
arrange(desc(poly_area)) %>%
slice(1) %>%
select(BoroName, geometry)
# ============================================================
# 3. 空间验证渲染:叠加瓦片底图与制图规范组件
# ============================================================
ggplot() +
# 载入 CartoDB Light 极简瓦片底图以建立地理语境
annotation_map_tile(type = "cartolight", zoom = 12, alpha = 0.9) +
# 渲染曼哈顿主岛边界要素:设置极简视觉特征
geom_sf(data = manhattan_boundary, aes(fill = "Study Area"),
color = "darkred", linewidth = 0.6, alpha = 0.1) +
# 配置空间参考组件:比例尺与指北针,确保地图工程学规范
scale_fill_manual(values = c("Study Area" = "darkred"), name = NULL) +
annotation_scale(
location = "bl", width_hint = 0.25, style = "ticks",
text_cex = 0.8, text_col = "gray30"
) +
annotation_north_arrow(
location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(
fill = c("gray40", "white"), line_col = "gray20"
)
) +
# 全局主题定制:聚焦地理要素展示
theme_bw() +
theme(
legend.position = "bottom",
legend.text = element_text(size = 10, face = "bold"),
plot.title = element_text(face = "bold", hjust = 0.5),
panel.grid.major = element_line(color = "gray90", linetype = "dashed")
) +
labs(
title = "Manhattan Shoreline-Clipped Boundary (Main Island)",
subtitle = "Data Source: NYC Open Data ArcGIS API",
caption = "Coordinate System: WGS84 | Basemap: CartoDB Light"
)# ============================================================
# 4. NYC Airbnb 房源数据摄取 (Inside Airbnb 动态源)
# ============================================================
# 指定远程数据源 URL(GZIP 压缩格式存储)
nyc_url <- "https://data.insideairbnb.com/united-states/ny/new-york-city/2025-11-01/data/listings.csv.gz"
# 执行内存级流式解压与结构化数据解析
nyc_raw <- read_csv(nyc_url)
# 可验证数据结构
# glimpse(nyc_raw)阶段性成果分析
目前,通过 ArcGIS REST API
接口集成与几何清洗逻辑(基于面积排序提取主岛实体),已成功界定了研究区域的边界数据(manhattan_boundary)。同时,利用流式摄取,纽约市的
Airbnb 全量原始数据(nyc_raw)也已完成载入。
数据特征与核心变量筛选
初步的结构透视显示,该数据集包含 36,353 个观测样本及 79 个维度变量。研究重心将聚焦于以下核心指标:
longitude(经度)与 latitude(纬度),构成了房源在地理空间中的几何坐标。price(价格),是衡量微观经济异质性与空间增值效应的关键统计变量。© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
在获取曼哈顿主岛边界(manhattan_boundary)与纽约市 Airbnb
原始房源数据(nyc_raw)后,本节针对原始数据的格式问题、极值干扰及分布偏态进行预处理,主要包含以下四个步骤:
NA)的样本。利用正则表达式剥离价格字段中的字符并将其数值化,同时设定有效租金区间($40 -
$3000),以控制极端值对后续空间统计的干扰。注:此租金位每晚租金
Mako)与浅色底图绘制曼哈顿房源微观空间分布图,初步展示租金在地理空间上的集聚特征与梯度分布。library(classInt) # 提供 Fisher-Jenks 自然断点分类算法
# ============================================================
# 1. 属性清洗与空间要素实例化 (Data Cleaning & Spatial Instantiation)
# ============================================================
manhattan_airbnb <- nyc_raw %>%
select(longitude, latitude, price) %>%
# 1.1 缺失值剔除与格式转化
filter(!is.na(longitude) & !is.na(latitude) & !is.na(price)) %>%
mutate(price_num = as.numeric(str_replace_all(price, "[\\$,]", ""))) %>%
# 1.2 极值截断:剔除统计异常值,约束至合理市场区间 ($40 - $3000)
filter(!is.na(price_num) & price_num >= 40 & price_num <= 3000) %>%
# 1.3 空间几何化与拓扑裁剪 (Point-in-Polygon)
st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>%
st_filter(manhattan_boundary, .predicate = st_intersects)
# ============================================================
# 2. 数据离散化:Fisher-Jenks 自然断点法 (Data Discretization)
# ============================================================
# 2.1 计算自然断点 (n = 7),最大化类间差异与类内同质性
breaks_fisher <- classIntervals(manhattan_airbnb$price_num, n = 7, style = "fisher")$brks
# 2.2 构建规范化图例标签
breaks_round <- round(breaks_fisher)
labels_fisher <- paste0("$", breaks_round[1:7], " - $", breaks_round[2:8])
# 2.3 基于断点生成有序分类变量 (Ordinal Variable)
manhattan_airbnb <- manhattan_airbnb %>%
mutate(price_class = cut(price_num,
breaks = breaks_fisher,
labels = labels_fisher,
include.lowest = TRUE))
# ============================================================
# 3. 空间分布可视化 (Spatial Distribution Mapping)
# ============================================================
ggplot() +
# 3.1 地理语境层:加载极简浅色底图
annotation_map_tile(type = "cartolight", zoom = 13, alpha = 0.5) +
# 3.2 边界约束层:绘制研究区轮廓,并触发线型图例
geom_sf(data = manhattan_boundary, aes(linetype = "Study Area Boundary"),
fill = NA, color = "black", linewidth = 0.5, alpha = 0.8) +
scale_linetype_manual(values = c("Study Area Boundary" = "solid"), name = NULL) +
# 3.3 核心要素层:微观点渲染与离散色彩映射
geom_sf(data = manhattan_airbnb, aes(color = price_class), size = 0.1, alpha = 0.8) +
scale_color_viridis_d(option = "mako",
name = "Nightly Price",
direction = -1) +
# 3.4 图例排版:强制反转价格图例序,放大图例点,并置顶边界图例
guides(
color = guide_legend(reverse = TRUE, override.aes = list(size = 2, alpha = 1)),
linetype = guide_legend(order = 1)
) +
# 3.5 空间参考组件:比例尺与指北针
coord_sf(expand = TRUE) +
annotation_scale(location = "bl", width_hint = 0.2) +
annotation_north_arrow(location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(text_col = "grey20", line_col = "grey40")) +
# 3.6 学术排版主题配置
theme_bw() +
theme(
legend.position = "right",
legend.title = element_text(face = "bold", size = 9),
legend.text = element_text(size = 8),
legend.spacing.y = unit(0.2, "cm"),
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(color = "gray30", hjust = 0.5),
panel.grid = element_blank(),
axis.text = element_text(size = 8, color = "gray40"),
axis.title = element_blank()
) +
labs(
title = "Airbnb Price Distribution in Manhattan",
subtitle = paste0("Fisher-Jenks Classification | N = ", scales::comma(nrow(manhattan_airbnb))),
caption = "Basemap: CartoDB Light | Price bounded: $40 - $3000"
)阶段性成果分析
至此,预处理后的 Airbnb 房源点已通过分层设色方式(图中颜色由浅入深表征租金梯度增长)映射在曼哈顿主岛底图上。
当前结果评估
目前的地图展示了研究区域内房源的空间分布密度与价格层级特征。然而,这种基于原始数据的直接视觉呈现(Raw Data Mapping)仍存在分析局限:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
在微观尺度下,离散的点状数据 (Point Pattern) 极易受局部极值或随机噪声干扰。此外,庞大的点位样本不仅增加“空间过拟合”风险,也显著抬高了后续空间建模与自相关检验(如 Moran’s I)的计算开销。为此,本节引入空间离散化方法 (第四章提及过部分内容),将连续的地理空间划分为标准化的面状分析单元以实现数据降维。
本节的实操将围绕以下四个核心步骤展开:
# ============================================================
# 1. 投影系转换 (Planar Projection Transformation)
# ============================================================
# [科学依据]: 面积与距离的拓扑计算必须在平面投影坐标系中进行。
# 转换至纽约市官方标定系 EPSG:2263 (NAD83 / New York Long Island)。
# [注意]: 此坐标系的测量基准单位为 US Survey Foot (英尺),而非国际标准米。
manhattan_boundary_proj <- st_transform(manhattan_boundary, 2263)
manhattan_airbnb_proj <- st_transform(manhattan_airbnb, 2263)
# ============================================================
# 2. 空间密铺与降维参数推导 (Hexagonal Tessellation)
# ============================================================
# 2.1 面积逆推导 (基于 15-Minute City 理论尺度)
# 参考微观城市可达性研究,设定基础分析单元面积约为 0.1 平方公里
target_area_m2 <- 100000 # 目标面积: 0.1 km² = 100,000 m²
# 依据正六边形面积公式 A = (sqrt(3)/2) * h^2,逆推对边间距 (h)
cellsize_m <- sqrt((target_area_m2 * 2) / sqrt(3))
# 单位换算:将公制 (Meter) 转换为目标坐标系的英制 (Survey Foot)
cellsize_ft <- cellsize_m * 3.280839895
# [参数记录]:
# 理论基础: 15分钟城市微观空间单元 (0.1 km²)
# 推导对边距 (h): 约 339.81 m (约 1114.86 ft)
# 2.2 构建六边形空间格网矩阵
hex_grid <- st_make_grid(
manhattan_boundary_proj,
cellsize = cellsize_ft, # 动态传入理论推导值
square = FALSE # 启用六边形拓扑 (Isotropic Hexagons)
) %>%
st_sf() %>%
mutate(hex_id = row_number()) # 分配唯一空间标识符
# 2.3 边界拓扑裁剪 (Boundary Clipping)
# 运用空间相交谓词 (st_intersects) 剔除完全位于水域的无效网格
hex_grid_manhattan <- hex_grid %>%
st_filter(manhattan_boundary_proj, .predicate = st_intersects)
# ============================================================
# 3. 空间连接与属性聚合 (Spatial Join & Aggregation)
# ============================================================
hex_airbnb_stats <- hex_grid_manhattan %>%
# 执行点对面的空间映射 (Point-in-Polygon)
st_join(manhattan_airbnb_proj, join = st_intersects) %>%
group_by(hex_id) %>%
summarise(
listing_count = sum(!is.na(price_num)),
median_price = median(price_num, na.rm = TRUE) # 提取中位数以平滑极值
) %>%
# [小样本偏差控制 (Small Area Estimation Bias Control)]
# 依据数据第一四分位数 (1st Quantile),设定最小样本量为 5。
# 此举有效剥离了极端低密度区域的统计噪声,确保 Median_Price 的统计鲁棒性。
# [注]: 过滤后,预计保留的有效曼哈顿网格数量约为 300-380 个。
filter(listing_count >= 5)
# ============================================================
# 4. 格局可视化预处理与出图 (Choropleth Mapping)
# ============================================================
# 4.1 逆向重投影:转回 WGS84 (EPSG:4326) 以精确对齐 Web 底图
hex_airbnb_wgs84 <- st_transform(hex_airbnb_stats, 4326)
# 4.2 数据离散化:应用 Fisher-Jenks 算法 (Natural Breaks)
# 寻找数据中的自然聚类断点,最大化类间方差,最小化类内方差
breaks_hex_fisher <- classIntervals(hex_airbnb_wgs84$median_price, n = 7, style = "fisher")$brks
breaks_hex_round <- round(breaks_hex_fisher)
labels_hex_fisher <- paste0("$", breaks_hex_round[1:7], " - $", breaks_hex_round[2:8])
# 实例化有序分类因子
hex_airbnb_wgs84 <- hex_airbnb_wgs84 %>%
mutate(price_class = cut(median_price,
breaks = breaks_hex_fisher,
labels = labels_hex_fisher,
include.lowest = TRUE))
# 4.3 渲染空间分布热力图
ggplot() +
# 语境层:加载极简 CartoDB 底图,弱化背景干扰
annotation_map_tile(type = "cartolight", zoom = 13, alpha = 0.5) +
# 边界层:勾勒研究区确切轮廓
geom_sf(data = manhattan_boundary, fill = NA, color = "black", linewidth = 0.5) +
# 核心信息层:基于离散化的租金中位数填充六边形网格
geom_sf(data = hex_airbnb_wgs84, aes(fill = price_class),
color = "black", linewidth = 0.1, alpha = 0.75) +
# 色彩映射:Magma 离散色盘 (深色系表征高溢价区)
scale_fill_viridis_d(option = "magma",
name = "Median Price\n(Fisher-Jenks)",
direction = -1) +
# 图例优化:高值置顶,顺应空间认知直觉
guides(fill = guide_legend(reverse = TRUE)) +
# 空间参考系:比例尺与指北针
coord_sf(expand = TRUE) +
annotation_scale(location = "bl", width_hint = 0.2) +
annotation_north_arrow(location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(text_col = "grey20", line_col = "grey40")) +
# 学术主题框架
theme_bw() +
theme(
legend.position = "right",
legend.title = element_text(face = "bold", size = 9),
legend.text = element_text(size = 8),
legend.spacing.y = unit(0.2, "cm"),
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(color = "gray30", hjust = 0.5),
panel.grid = element_blank(),
axis.text = element_text(size = 8, color = "gray40"),
axis.title = element_blank()
) +
labs(
title = "Aggregated Airbnb Median Price in Manhattan",
subtitle = paste0("15-Min City Spatial Binning (~0.10 sq.km) | N_Hex = ", nrow(hex_airbnb_wgs84)),
caption = "Basemap: CartoDB Light | Filter: Listing Count >= 5"
)概念起源与定义:
“15分钟城市”概念由法国索邦大学教授 Carlos Moreno
提出,并在后疫情时代迅速成为全球城市规划界的焦点。其核心理念是“超本地化”(Hyper-proximity):居民只需步行或骑行 15 分钟(通常对应约 \(1 - 1.5\text{
km}\)
的空间半径),即可满足工作、购物、教育、医疗和休闲等大部分日常需求。
为何成为空间研究热点?
传统城市研究往往受限于宏观行政区划(如 Census Tracts)。而
15分钟城市理论促使学者们将目光转向更微观的“人本尺度(Human-scale)”。它不仅是实现低碳减排的政策工具,更是衡量城市空间公平(Spatial
Equity)与资源可达性(Accessibility)的重要理论框架。在
GIS
空间建模中,为了捕捉这种微观的邻里溢出效应,学者们通常抛弃大尺度网格,转而采用面积约
\(0.1 - 0.5\text{ km}^2\)
的高分辨率空间分析单元(如 Uber H3 算法的底层网格,或 5
分钟核心步行圈),这也正是本节代码中面积参数推导的理论基石。
Figure 5.5. 15分钟城市概念图
阶段性成果分析
至此,微观离散的房源点数据已转化为基于“15分钟城市”理论尺度的六边形网格面。通过聚合提取网格内的租金中位数并过滤低频噪点,该空间降维操作有效剥离了局部的极端异常值,呈现出平滑且稳健的租金空间梯度分布。
当前结果评估
观察网格化后的空间热力图,可直观识别出曼哈顿 Airbnb 市场的空间异质性与集聚特征。具体而言,高租金网格明显集聚于曼哈顿中城(中央公园部分)与下城(主岛南部),而低租金网格则集中分布于曼哈顿北部。
然而,仅凭视觉观测(Visual Inspection)无法严谨量化这种空间集聚的统计强度,亦难以排除随机分布的偶然性。
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
前面六边形网格热力图初步揭示了曼哈顿 Airbnb
租金在空间上的集聚倾向。
然而,单纯的视觉判读具有主观性。为更加严谨验证该空间异质性是否具备统计学支撑,本节引入探索性空间数据分析(ESDA)的核心工具——空间自相关(Spatial Autocorrelation)模型。
本节的实操验证围绕以下三个关键步骤展开:
zero.policy = TRUE 容错机制,以保障空间滞后项(Spatial Lag)计算的顺利执行。“Everything is related to everything else, but near things are more related than distant things”
1970年,地理学家 Waldo Tobler 提出了著名的空间理论基石:“任何事物都与其他事物相关联,但相近的事物关联更紧密”。这一论断为理解空间与空间要素的溢出效应提供了底层逻辑。
Figure 5.6. 空间自相关概念图
# 载入空间自相关核心依赖包
library(spdep)
# ============================================================
# 1. 构建 Queen 邻接空间权重矩阵 (Queen Contiguity)
# ============================================================
# 1.1 基于多边形边界的相接关系构建邻接列表 (默认 queen = TRUE)
hex_nb <- poly2nb(hex_airbnb_stats)
# 1.2 转化为行标准化的空间权重列表 (style = "W")
# [核心参数]: zero.policy = TRUE 允许存在没有邻居的"空间孤岛"
# 算法会自动将这些孤岛的空间滞后项设为 0,避免程序报错中断
hex_listw <- nb2listw(hex_nb, style = "W", zero.policy = TRUE)
# ============================================================
# 2. 全局空间自相关检验 (Global Moran's I)
# ============================================================
# 2.1 执行 Global Moran's I 统计检验
global_moran <- moran.test(hex_airbnb_stats$median_price, hex_listw, zero.policy = TRUE)
# ============================================================
# 3. 绘制高阶 Moran 散点图 (Moran Scatter Plot)
# ============================================================
# 3.1 提取并中心化原始值 (当前网格租金)
price_scaled <- as.numeric(scale(hex_airbnb_stats$median_price))
# 3.2 计算空间滞后值 (周围相邻网格租金的加权平均)
lag_scaled <- lag.listw(hex_listw, price_scaled, zero.policy = TRUE)
# 3.3 构建用于绘图的数据框
moran_df <- data.frame(
Price_Scaled = price_scaled,
Spatial_Lag = lag_scaled
)
# 3.4 使用 ggplot2 绘制符合学术审美的 Moran 散点图
p_moran_scatter <- ggplot(moran_df, aes(x = Price_Scaled, y = Spatial_Lag)) +
# 散点图层:透明度处理以应对点重叠
geom_point(alpha = 0.6, color = "gray40", size = 1.5) +
# 拟合线层:红色实线代表 Moran's I 的线性趋势
geom_smooth(method = "lm", color = "firebrick", se = TRUE, fill = "lightpink", alpha = 0.3) +
# 象限分割线:虚线划分 HH, LH, LL, HL 四个象限
geom_hline(yintercept = 0, linetype = "dashed", color = "black", linewidth = 0.5) +
geom_vline(xintercept = 0, linetype = "dashed", color = "black", linewidth = 0.5) +
# 学术主题与标签配置
theme_bw() +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(color = "gray30", hjust = 0.5),
panel.grid.minor = element_blank()
) +
labs(
title = "Moran Scatter Plot of Airbnb Median Price",
subtitle = paste0("Global Moran's I = ", round(global_moran$estimate[1], 3),
" (p-value < 0.001) | Spatial Weights: Queen Contiguity"),
x = "Standardised Median Price",
y = "Standardised Spatial Lag"
)+ coord_fixed()
# 渲染出图
p_moran_scatter阶段性成果分析
至此,基于 Queen 邻接标准构建的空间权重矩阵,本研究执行了全局 Moran’s I 统计检验,并输出标准化的 Moran 散点图。 该步骤将前期对地图的直观视觉感知正式转化为严谨的定量统计结论。
当前结果评估
观察 Moran 散点图可知,数据拟合线呈现显著的左下至右上倾斜倾向(斜率为正)。大量网格样本集中分布于第一象限(高-高集聚,HH)与第三象限(低-低集聚,LL)。结合高度显著的统计学检验结果(p-value < 0.001),该模型确凿地证实了曼哈顿 Airbnb 租金存在强烈的正向空间自相关——即高租金与高租金相邻、低租金与低租金相邻。
然而,全局 Moran’s I 仅从宏观层面证明了全域范围内存在显著的集聚模式,却无法指出这些高/低值集聚的具体地理边界。为精准定位具备统计学意义的空间冷热点,后续分析亟需从全局尺度下沉至局部尺度,引入局部空间自相关指标(Local Moran’s I / LISA)进行微观的空间格局解构。
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
上一节的全局 Moran’s I 检验已证实曼哈顿 Airbnb 租金存在显著的整体空间依赖性。然而,全局统计量假定空间过程具有平稳性(Spatial Stationarity),从而掩盖了局部尺度的空间异质性与具体的集聚地理位置。为精准定位高溢价区与平价洼地,本节引入局部空间自相关分析。
实操流程涵盖以下三个核心环节:
zero.policy
机制处理空间孤岛。参考上一节产出的 Moran’s I 散点图
Figure 5.7. Moran’s I 散点图象限解读
什么是 LISA?
局部空间关联指标(Local Indicators of Spatial Association, LISA)由
Luc Anselin 于 1995 年提出。它本质上是全局 Moran’s I
的局部化分解形式,能够衡量单个空间单元与其周边邻居在属性值上的相似程度或差异程度,同时附带统计显著性检验。
为什么需要做 LISA?(与全局自相关的关系)
全局
Moran’s I 提供的是全域的“平均趋势”,但无法回答“集聚发生在哪里”。只要进行了空间自相关分析,LISA
几乎是必不可少的后续步骤:
推荐拓展阅读:
# ============================================================
# 4. 局部空间自相关探测 (Local Indicators of Spatial Association, LISA)
# ============================================================
# 4.1 计算 Local Moran's I 统计量 (沿用 zero.policy 容忍空间孤岛)
local_m <- localmoran(hex_airbnb_stats$median_price, hex_listw, zero.policy = TRUE)
# 4.2 设定显著性阈值 (alpha = 0.05) 并提取推断 P 值
alpha <- 0.05
p_values <- local_m[, 5] # 提取矩阵第 5 列: Pr(z != E(Ii))
# 初始化象限向量,默认归类为统计不显著 ("Non-Significant")
quadrant <- rep("Non-Significant", nrow(hex_airbnb_stats))
# 基于显著性过滤与中心/滞后项的正负离差,执行 LISA 空间象限划分
quadrant[price_scaled > 0 & lag_scaled > 0 & p_values <= alpha] <- "High-High"
quadrant[price_scaled < 0 & lag_scaled < 0 & p_values <= alpha] <- "Low-Low"
quadrant[price_scaled > 0 & lag_scaled < 0 & p_values <= alpha] <- "High-Low"
quadrant[price_scaled < 0 & lag_scaled > 0 & p_values <= alpha] <- "Low-High"
# 4.3 实例化为有序因子变量,并绑定至制图数据框 (EPSG:4326)
hex_airbnb_wgs84$lisa_cluster <- factor(quadrant,
levels = c("High-High", "Low-Low",
"High-Low", "Low-High",
"Non-Significant"))
# ============================================================
# 5. LISA 空间聚类格局可视化
# ============================================================
# 参照 GeoDa 标准构建 LISA 聚类学术配色字典
lisa_colors <- c("High-High" = "#D7191C", # 高-高集聚区 (热点)
"Low-Low" = "#2C7BB6", # 低-低集聚区 (冷点)
"High-Low" = "#FDAE61", # 高-低空间异常
"Low-High" = "#ABD9E9", # 低-高空间异常
"Non-Significant" = "grey90") # 统计不显著区
# 执行空间渲染
p_lisa_map <- ggplot() +
# 语境底图与研究区边界图层
annotation_map_tile(type = "cartolight", zoom = 13, alpha = 0.5) +
geom_sf(data = manhattan_boundary, fill = NA, color = "black", linewidth = 0.5) +
# LISA 聚类要素面状渲染
geom_sf(data = hex_airbnb_wgs84, aes(fill = lisa_cluster),
color = "white", linewidth = 0.1, alpha = 0.85) +
# 离散色彩映射
scale_fill_manual(values = lisa_colors, name = "LISA Clusters\n(p <= 0.05)", drop = FALSE) +
# 地图学要素配置 (比例尺、指北针)
coord_sf(expand = TRUE) +
annotation_scale(location = "bl", width_hint = 0.2) +
annotation_north_arrow(location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(text_col = "grey20", line_col = "grey40")) +
# 学术图表排版主题
theme_bw() +
theme(
legend.position = "right",
legend.title = element_text(face = "bold", size = 9),
legend.text = element_text(size = 8),
legend.spacing.y = unit(0.2, "cm"),
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(color = "gray30", hjust = 0.5),
panel.grid = element_blank(),
axis.text = element_text(size = 8, color = "gray40"),
axis.title = element_blank()
) +
labs(
title = "Local Indicators of Spatial Association (LISA)",
subtitle = "Manhattan Airbnb Rent Clustering (Hexagonal Binning)",
caption = "Spatial Weights: Queen Contiguity | Zero.policy = TRUE"
)
# 渲染出图
p_lisa_map阶段性成果评估
至此,研究通过局部空间自相关(LISA)分析,突破了全局统计量的平稳性局限。基于 \(\alpha = 0.05\) 的显著性阈值,测度并提取了曼哈顿 Airbnb 租金的微观空间集聚冷热点边界。
空间格局解构
观察 LISA 聚类地图,曼哈顿 Airbnb 租金呈现高度极化的空间冷热点格局:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
重要
在完整的学术研究(特别是论文写作中),对已有研究的回顾总结与对潜在局限性的反思是重要的收尾环节。明确 “研究证实了什么” 以及 “研究未能解决什么”,不仅是科学严谨性的体现,更是启发未来研究方向的基石。
本章将针对前述专题研究1: “曼哈顿 Airbnb 租金空间异质性”这示例展开复盘。首先,必须承认,受限于教学场景与篇幅,该示例在课题设计与理论深度上并非一个绝对严苛的正式科研项目。然而,其所贯穿的探索性空间数据分析 (ESDA) 工作流,却是诸多真实空间计算社会科学与城市实证研究中的核心范式之一。
进阶阅读
概念:
探索性空间数据分析(Exploratory
Spatial Data Analysis, ESDA)
是传统探索性数据分析 (EDA)
(参考本课程第二章)
在空间科学领域的延伸。该方法论结合了空间统计学与地理地图可视化技术,旨在识别属性数据的空间分布模式、探测空间自相关性
(Spatial Autocorrelation) 与
空间异质性 (Spatial
Heterogeneity),并揭示潜在的空间异常值 (Spatial Outliers)。
核心价值:
在构建复杂的空间计量回归模型之前
(如,地理空间加权回归, GWR),ESDA
是不可或缺的前置检验环节。其核心分析工具能够将主观的地图视觉感知转化为严谨的定量统计推断。
推荐拓展资源 (基于 R
语言):
为进一步掌握 R
语言在空间分析中的应用,可参考以下权威开源学术教程:
Spatial Data Science: With Applications in R
(Edzer Pebesma 等著):
该书的第 15
章专门针对空间自相关进行了基于 R
语言的分析案例探索与实操。
🔗
https://r-spatial.org/book/15-Measures
回顾专题研究 1,研究旨在深入探讨曼哈顿 Airbnb 市场的空间分布格局与租金异质性。围绕这一目标,研究执行了从数据预处理到空间统计推断的完整 ESDA 流程。具体核心工作流与关键技术节点总结如下:
核心数据摄取与空间实例化:
分析依托两类核心数据展开。首先,通过官方接口获取纽约市边界,利用几何面积计算提取了曼哈顿主岛作为研究基底。随后,对流式摄取的
Airbnb 原始表格数据执行属性清洗与极值截断 ($40 -
$3000),并通过 st_as_sf()
函数将其转化为空间对象,最后利用空间相交运算完成拓扑裁剪。
基础映射与网格化降维重构:
在采用
Fisher-Jenks
算法完成初始散点可视化后,针对局部严重的视觉重叠现象,研究引入了“15分钟城市”理论框架。通过逆推 \(0.1\text{ km}^2\) 单元面积设定
cellsize,构建了高分辨率的六边形网格密铺 (Hexagonal
Binning)。运用 st_join()
将点数据映射至网格,聚合提取租金中位数,并设定保留阈值
(listing_count >= 5)
有效规避了小样本统计偏差。降维后使用Fisher-Jenk分类方法呈现的空间热力图初步揭示了区域集聚倾向。
空间自相关检验与冷热点标定:
为从统计学层面客观证实上述视觉集聚,研究构建了 Queen
一阶邻接空间权重矩阵 (并开启
zero.policy = TRUE
容错机制处理空间孤岛)。首先,通过计算全局 Moran’s
I 统计量,验证了全域范围内的正向空间依赖性。在此基础上,进一步运用
LISA (局部空间自相关)
模型,从微观尺度精准锚定了中下城的高溢价热点
(HH) 与北部的低租金冷点 (LL)。
重要
从“知其然”到“知其所以然”
任何数据分析模型的构建都伴随着一系列的主观参数设定与方法论妥协。尽管前述的探索性空间数据分析 (ESDA) 工作流揭示了曼哈顿 Airbnb 租金的空间集聚特征,但在严谨的学术视角下,该流程中诸多核心参数的选择与现象背后的机制仍具有广阔的推敲与反思空间。
以下五个维度的问题,旨在激发面对空间数据分析结果时的批判性思考:
底层数据结构的时效性与稳健性考量:
本实操案例选取了 2025-11-01 这一特定时间切片的截面数据。然而,必须厘清的是,Airbnb
租金本质上属于高度动态的报价数据 (Asking
Price),不可避免地受制于强烈的时序波动与季节性周期。同一套房源在旅游旺季与淡季的定价策略是否存在显著差异?部分房源在特定月份可能因未开放预订而在此次截面数据中“隐身”,这种必然的样本缺失是否会扭曲局部的空间集聚特征?若要追求更为稳健且普适的空间格局规律,是否应当打破单月截面的局限,汇总整合特定年份
(如 2025 全年)
的纵向面板数据,以聚合年度均价的方式来过滤短期的时序噪声 (Temporal
Noise)?这提示了在空间建模前,透彻理解数据生成机制
(Data Generating Process, DGP)
及其潜在偏差的必要性。
极值截断的科学性探讨:
在初始预处理阶段,分析主观设定了每晚租金的有效区间 ($40 -
$3000)。然而,这种一刀切的截断是否具备坚实的统计学支撑?原始数据中极具迷惑性的
“0”
标价是系统录入错误还是特殊商业行为?超过上万美元的极值是真实的奢华套房还是异常噪点?在实际科研中,是否应强制引入直方图或箱线图
(Boxplot) 进行严密的分布检验,进而利用 IQR
(四分位距) 或 Z-Score
法则进行更为科学的异常值剥离?此外,高达 $3000
的上限阈值,对于真实的微观住宿市场而言,是否仍然过于宽泛而未能有效滤除噪音?
网格过滤阈值的统计鲁棒性:
在执行六边形网格降维时,算法剔除了房源数量少于5
套的单元。这一操作的初衷虽为控制小样本估计偏差,但“阈值为
5”的合理性何在?面对城市空间分布的非均匀性,盲目过滤是否会意外抹除边缘地带的真实市场微弱特征?是否应当通过对各网格内样本密度的深入频率分布检验,来寻找更为客观的截断断点?
空间权重矩阵的拓扑局限:
空间自相关检验高度依赖于空间权重矩阵的设定。本研究采用了基于共边或共点的Queen邻接规则,并开启了
zero.policy = TRUE
以被动忽略无邻居的“空间孤岛”。然而,这种纯粹的拓扑定义是否完全契合城市经济要素的实际逻辑?对于那些被剥离的孤岛网格,直接忽略是否会导致空间信息的折损?相比之下,采用基于距离衰减的权重矩阵,或是引入K 最近邻 (KNN)
算法,是否能建立更为健全且无孤岛的相邻关系网络?
从“空间模式”走向“驱动机制”:后续研究
LISA 聚类地图成功揭示了中下城的高溢价热点 (HH)与北部的低租金冷点
(LL)。但这仅仅回答了“现象是什么”(Spatial
Pattern),更为深刻的科学命题在于“现象因何而生”(Spatial
Process)。中下城的集聚是否源于其不可替代的区位优势、密集的人口流动、亦或是特定的商业用地类型?北部洼地又折射出怎样的社会经济基础与建成环境特征?
概念:
空间权重矩阵
(Spatial Weights Matrix, 常记为 \(W\))
是空间统计学中的核心组件。 它通过 \(n \times n\)
的矩阵结构,形式化地表达了地理空间中各个观测单元之间的拓扑相邻或空间邻近关系,是计算空间自相关与构建空间计量模型的前置基础。
Figure 5.8. 空间毗邻矩阵示意图
核心构建准则:
定义“谁是谁的邻居”通常依赖于以下两类几何或距离标准:
Figure 5.9. Queen / Rook 邻接示意图
2. 基于距离 (Distance-based):多基于要素的几何质心 (Centroid) 或点数据计算。
Figure 5.10. 距离阈值 / KNN 邻接示意图
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
多源空间点数据分析与可达性工作流
“从离散点位到热点识别与可达性测度”
本节以上海市微博签到与交通 POI 数据为例,介绍多源空间点数据分析的基本流程,包括空间裁取与预处理、核密度估计 (KDE)、AOI 提取与交通可达性测度。
点击下方卡片,快速跳转至相应模块:
课题与目标
核心研究框架
区域与数据
空间边界与载入
数据预处理
拓扑裁剪与校验
核密度估计
连续活力面重构
极核提取
AOI边界划定
空间可达性
交通节点距离对比
💡 提示:学习完一个小节后,请再次点击 屏幕右下角的专题导航按钮回到本导航页
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
重要 · 实战教学
本节以上海市(Shanghai)为例,演示两类空间点数据的联合分析流程:一类为带地理坐标的微博签到/发布点(geotagged Weibo posts/check-ins),用于刻画城市数字活动的空间分布;另一类为公共交通设施 POI(metro stations, bus stops),用于表征交通服务供给与可达性条件。
研究区选取上海主城向郊区过渡的典型区域——闵行区(Minhang District),构建“热点识别 → 空间单元提取 → 可达性度量 → 对比验证”的探索性空间分析工作流。
示例课题
研究课题:
城市数字活力的空间分布与公共交通可达性分析:基于核密度估计与最近邻距离
研究背景与目标:
地理坐标社交媒体数据可作为观察人群活动强度与空间集聚的补充证据;公共交通站点等设施点位常用于衡量交通服务覆盖与空间公平性(Spatial
Equity)。本节聚焦闵行区,完成以下三项分析任务:
研究区界定与坐标系处理:
统一坐标参考系(CRS
transformation),将微博点与交通设施点裁剪至研究边界(Point-in-Polygon
clipping),并在底图上展示点位分布以形成初步空间判断。
热点强度表面构建与高值区提取:
采用二维核密度估计(KDE, Kernel Density
Estimation)生成连续强度表面,并以分位数阈值(如上 5%)提取高值区域;将其转换为多边形单元(AOI, Area of
Interest),用于后续统计与空间对比。
公共交通可达性度量与耦合对比:
在“高活力
AOI”与“非 AOI”两类区域内,使用最近邻距离(Nearest
Neighbour
distance)计算观测点到地铁站与公交站的直线距离分布;通过分布对比,量化两类区域的差异,并检验公共交通设施与数字活动热点的空间关联。
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
本节将聚焦中国超大城市(Megacity)的典型代表——上海市,并以承载丰富高校与科创资源的闵行区(Minhang District)为核心,开展基于社交媒体数据(微博)的微观数字活力空间探索。作为主城向郊区过渡的典型复合型空间,闵行区为理解现代城市空间结构与数字活力分布提供了极为理想的实证样本。
上海市地处长江入海口,是具有全球影响力的国际化大都市与科创中心。全市现辖 16 个行政区,涵盖黄浦、徐汇等传统核心区,以及浦东新区、闵行等重要发展腹地。本节的空间点模式分析将主要聚焦于其地理几何中心——闵行区。
数据获取
本阶段的任务是获取本空间分析课题所需的三个核心数据集:
官方行政边界、城市实体
POI(公共交通站点) 与 微博签到原始数据。
代码逻辑解析:
Step 1
多源空间数据的流式摄取与坐标挂载(数据下载与读取)
本研究的微观活力数据(微博签到打卡数据)与建成环境数据(上海市公交类POI数据)均托管于开源 GitHub
仓库。代码首先获取了上海市2022-2025年微博签到4%样本的
.csv 表格 (weibo_sample_4pct.csv),随后读取了包含地铁站与公交站的
.geojson 矢量文件(地铁站.geojson与公交站.geojson)。其中关键步骤在于编码与投影规范化:在读取 POI 数据时强制设定
UTF-8 编码,并直接挂载全球通用的
WGS84(EPSG:4326) 参考系。
下方代码采用了本地缓存读取替代实时在线拉取,提升 Knit 渲染的稳定性与效率。
Step 2
上海市行政边界的投影转换与靶向提取(研究范围界定)
代码对接了 2024
版天地图国家地理信息公共服务平台的边界数据(shanghai_boundary.geojson)。由于国内官方原始数据底层多为
CGCS2000(EPSG:4490),代码首先利用
st_transform() 将其统一转换为
WGS84 投影,以适应后续标准瓦片底图渲染。随后,通过属性表中的行政区划代码(县代码 == "310112")进行筛选,截取出闵行区实体边界,作为本研究的研究区域。
Step 3
地理语境下的空间验证与制图(可视化校验)
在处理多源异构的地理数据时,视觉验证是确保坐标系完全对齐的必要环节。代码利用
ggspatial 插件对接了高德公开瓦片底图
(Amap
XYZ),将上海市全域轮廓置于高德地图中,并使用darkred对闵行研究区进行高亮填充与质心文本标注。
# ==============================================================================
# 1. 依赖库加载与地理信息环境配置 (Environment Setup & Package Loading)
# ==============================================================================
library(tidyverse)
library(sf)
library(ggspatial) # 空间数据可视化扩展 (Tile basemaps & cartography)
library(showtext) # 全局字体渲染支持 (解决 ggplot2 中文字符乱码缺陷)
# 【新增核心算法包】:为后续的高阶空间分析提前装载环境
library(MASS) # 提供强大的 kde2d 二维核密度估计算法
library(stars) # 栅格数据处理与等值面提取引擎 (用于构建 AOI 边界)
showtext_auto()
# ==============================================================================
# 2. 核心数据源摄取:微博签到点、实体 POI 与官方行政边界
# ==============================================================================
# 2.1 摄取微博签到点属性数据 (CSV 表格格式,暂无空间几何特征)
# 教学提示:原代码通过 GitHub 远程拉取数据。为提升 RMarkdown Knit 本地渲染速度,此处改为读取本地 data 文件夹中的缓存数据。
# weibo_url <- "https://raw.githubusercontent.com/DAWN-ECNU/Example_data/main/weibo_sample_4pct.csv"
# weibo_raw <- read_csv(weibo_url)
weibo_raw <- read_csv("data/weibo_sample_4pct.csv")
# 2.2 摄取多类城市实体 POI 空间点数据 (GeoJSON 格式)
# 教学提示:同上,保留原 GitHub 在线读取逻辑作为参考,实际运行采用本地相对路径读取。
# base_poi_url <- "https://raw.githubusercontent.com/DAWN-ECNU/Example_data/main/"
# poi_bus <- st_read(URLencode(paste0(base_poi_url, "公交站.geojson")), options = "ENCODING=UTF-8") %>% st_set_crs(4326)
# poi_subway <- st_read(URLencode(paste0(base_poi_url, "地铁站.geojson")), options = "ENCODING=UTF-8") %>% st_set_crs(4326)
# 依次读取本地各类别 POI。强制设定 UTF-8 编码并挂载 WGS84 (EPSG:4326) 坐标系
poi_bus <- st_read("data/公交站.geojson", options = "ENCODING=UTF-8", quiet = TRUE) %>% st_set_crs(4326)
poi_subway <- st_read("data/地铁站.geojson", options = "ENCODING=UTF-8", quiet = TRUE) %>% st_set_crs(4326)
# 2.3 摄取上海官方行政边界 (源自 2024 版天地图国家地理信息公共服务平台)
# shanghai_boundary_url <- "https://raw.githubusercontent.com/DAWN-ECNU/Example_data/main/shanghai_boundary.geojson"
# shanghai_boundary <- st_read(shanghai_boundary_url) %>% st_transform(4326)
# 投影变换:底层数据为 CGCS2000 (EPSG:4490),此处统一转换为 WGS84 (EPSG:4326) 以适应国际标准瓦片底图渲染
shanghai_boundary <- st_read("data/shanghai_boundary.geojson", quiet = TRUE) %>%
st_transform(4326)
shanghai_districts <- shanghai_boundary
# 拓扑截取:根据国家行政区划代码 (adcode) 提取闵行区实体边界 (310112)
minhang_boundary <- shanghai_districts %>%
filter(县代码 == "310112")
# ==============================================================================
# 3. 研究区域可视化定位 (Contextual Mapping)
# ==============================================================================
# 【瓦片接口配置】定义高德公开 XYZ 瓦片链接
amap_xyz <- "http://wprd01.is.autonavi.com/appmaptile?x=${x}&y=${y}&z=${z}&lang=zh_cn&size=1&scl=1&style=7&ext=.png"
ggplot() +
# 3.1 载入高德瓦片底图建立地理语境 (调低 alpha 降低背景视觉权重,突出前景要素)
annotation_map_tile(type = amap_xyz, zoom = 11, alpha = 0.4) +
# 3.2 叠加空间几何要素:渲染全域灰色底框,并以主题色高亮闵行研究区 (采用 UK spelling: colour/grey)
geom_sf(data = shanghai_districts, fill = NA, colour = "grey20", linewidth = 0.5) +
geom_sf(data = minhang_boundary, aes(fill = "Study Area"),
colour = "darkred", linewidth = 0.6, alpha = 0.15) +
scale_fill_manual(values = c("Study Area" = "darkred"), name = NULL) +
# 3.3 标签映射:自动提取多边形质心 (Centroid) 进行文本锚定
geom_sf_text(data = minhang_boundary, aes(label = 县名),
size = 4, fontface = "bold", colour = "darkred") +
# 3.4 坐标系锚定:强制渲染引擎底层物理网格约束于 WGS84 (EPSG:4326)
coord_sf(crs = 4326, expand = TRUE) +
# 3.5 注入制图学标准组件:工程级比例尺与指北针
annotation_scale(
location = "bl", width_hint = 0.25, style = "ticks",
text_cex = 0.8, text_col = "grey20"
) +
annotation_north_arrow(
location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(
fill = c("black", "white"), line_col = "grey20"
)
) +
# 3.6 全局排版定制:建立严谨的学术图表视觉层级
theme_bw() +
theme(
legend.position = "bottom",
legend.text = element_text(size = 10, face = "bold"),
plot.title = element_text(face = "bold", hjust = 0.5),
panel.grid.major = element_line(colour = "grey90", linetype = "dashed")
) +
labs(
title = "Study Area: Minhang District, Shanghai",
subtitle = "Data Source: Tianditu 2024 Boundary & Weibo Sample Data",
caption = "Coordinate System: WGS84 (EPSG:4326) | Basemap: Amap"
)阶段性成果分析
目前,通过本地数据解析与空间属性筛选,已界定核心研究区的实体边界(minhang_boundary)。同时,城市公共交通站点数据(poi_bus,
poi_subway)与微博签到原始数据集(weibo_raw)均已完成加载,并依托高德瓦片底图实现了研究区域的空间落位与可视化校验。
当前结果评估
上述多源数据集构成了本研究的空间计算基础。后续分析将主要聚焦于以下两大核心维度:
经度(Longitude)与
纬度(Latitude),表征数字活力在地理空间中的几何锚点。© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
在获取闵行区边界(minhang_boundary)与全上海市微博签到原始数据集(weibo_raw)后,本节针对原始表格数据的几何缺失与空间越界问题进行预处理,主要包含以下三个核心步骤:
weibo_raw
中仅含数值坐标而无几何特征的问题,利用
st_as_sf() 将“经度”与“纬度”列转化为标准空间矢量要素(sf),并挂载全球通用参考系(EPSG:4326)。# ==============================================================================
# 4.1 空间实例化与拓扑裁剪
# ==============================================================================
# 1. 微博数据几何化:将 CSV 坐标列转化为 sf 空间对象 (WGS84)
weibo_sf <- weibo_raw %>%
st_as_sf(coords = c("经度", "纬度"), crs = 4326, remove = FALSE)
# 2. 空间相交裁剪 (Point-in-Polygon):仅保留落在闵行区边界内的散点
# 提示:st_intersection 会自动计算点与多边形的拓扑包含关系
weibo_minhang <- st_intersection(weibo_sf, minhang_boundary)
# ==============================================================================
# 4.2 空间分布基础可视化
# ==============================================================================
# 定义高德公开 XYZ 瓦片链接 (带 .png 伪装后缀防报错)
amap_xyz <- "http://wprd01.is.autonavi.com/appmaptile?x=${x}&y=${y}&z=${z}&lang=zh_cn&size=1&scl=1&style=7&ext=.png"
ggplot() +
# 1. 地理语境层:载入高德瓦片底图 (适当降低透明度以凸显数据点,zoom越大底图越细节)
annotation_map_tile(type = amap_xyz, zoom = 13, alpha = 0.6) +
# 2. 边界约束层:绘制闵行区轮廓,触发线型图例
geom_sf(data = minhang_boundary, aes(linetype = "Study Area Boundary"),
fill = NA, colour = "darkred", linewidth = .8, alpha = 0.8) +
scale_linetype_manual(values = c("Study Area Boundary" = "solid"), name = NULL) +
# 3. 核心要素层:渲染微博签到点
# 使用 aes(colour = ...) 触发分类图例,设置较低的 alpha 值应对点位重叠
geom_sf(data = weibo_minhang, aes(colour = "Weibo Check-ins"),
size = 1, alpha = 0.8, stroke = 0) +
# 设定散点颜色,保持视觉连贯性
scale_colour_manual(values = c("Weibo Check-ins" = "black"), name = NULL) +
# 4. 图例排版:分离线型与点状图例,强制放大点图例的尺寸与透明度便于阅读
guides(
linetype = guide_legend(order = 1),
colour = guide_legend(order = 2, override.aes = list(size = 3, alpha = 1))
) +
# 5. 空间参考组件:强制 WGS84 锚定,添加比例尺与指北针
coord_sf(crs = 4326, expand = TRUE) +
annotation_scale(
location = "bl", width_hint = 0.25, style = "ticks", text_col = "grey20"
) +
annotation_north_arrow(
location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(text_col = "grey20", line_col = "grey40")
) +
# 6. 学术排版主题配置
theme_bw() +
theme(
legend.position = "right",
legend.text = element_text(size = 9, face = "bold"),
legend.spacing.y = unit(0.2, "cm"),
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(colour = "grey30", hjust = 0.5),
panel.grid = element_blank(),
axis.text = element_text(size = 8, colour = "grey40"),
axis.title = element_blank()
) +
labs(
title = "Spatial Distribution of Weibo Check-ins",
# 动态插入裁剪后的有效点位数量
subtitle = paste0("Minhang District, Shanghai | N = ", scales::comma(nrow(weibo_minhang))),
caption = "Basemap: Amap | Coordinate System: GCJ-02 mapped to WGS84"
)阶段性成果分析
通过空间过滤,代码实现了从上海全域样本到闵行研究区域观测值的空间收敛。可视化结果显示,微博签到点在研究区内并非均匀分布,而是呈现出明显的空间异质性。初步识别出以虹桥枢纽、莘庄中心区、七宝老街以及紫竹高新区为核心的高强度活动簇群。
虹桥枢纽:研究区域西北部(最窄部分);莘庄、七宝:区域中段窄部; 紫竹高新区:区域南方底部
当前结果评估
当前的点图虽然展现了活动的地理分布,但由于点位重叠导致无法直观量化区域内的活力密度梯度。后续分析将聚焦于以下方向:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
在可视化了基础点位分布后,本节引入核密度估计(Kernel Density Estimation, KDE)方法,旨在将离散的社交媒体签到点转换为连续的活力表面,从而直观量化区域内部的空间集聚梯度。该过程主要包含以下两个核心步骤:
空间坐标分离:
由于 ggplot2
内部的二维密度统计算法无法直接解析空间要素的几何特征,需利用
st_coordinates() 提取独立的 X/Y
坐标列,并剥离其空间拓扑属性(st_drop_geometry),将其转化为纯数值数据框以加速底层运算。
重要
连续表面测算与渲染:
利用
stat_density_2d()
算法执行二维核密度计算。在视觉映射机制上,将模型输出的密度层级(level)同步绑定至填充色与透明度。配合热力色带(Inferno),使高活力核心呈现不透明的亮黄色,而低密度区则高透融入底图。此外,算法采用自动计算带宽(Automatic
Bandwidth)以客观反映数据的空间方差,并利用边界框严格锁定可视化视野。
核心原理与定义:
核密度估计(KDE)是一种用于估计随机变量概率密度函数的非参数空间统计方法。在地理空间分析中,它的核心机制是将离散的点要素(如微博签到点、交通事故、犯罪热点等)转化为连续的密度表面。
KDE
的算法逻辑在于:假设每个数据点上方都存在一个“隆起”的概率“山峰”(即核函数,Kernel
Function),通过将研究区域内所有点的“山峰”进行空间叠加,即可推算出空间中任意位置的相对密度梯度。
为什么带宽(Bandwidth)重要?
KDE
中关键的参数是带宽(也称搜索半径,Search
Radius)。带宽直接决定了密度表面的形态:带宽过大会导致过度平滑(Over-smoothing),掩盖局部的真实微观热点;带宽过小则会导致欠平滑(Under-smoothing),使表面产生大量破碎的“伪孤岛”。在学术实证中,带宽的选择需结合数据的统计学方差(如本节代码底层的自动算法)或特定的物理空间意义(如 1000 米的步行影响半径)来审慎决定。
推荐拓展阅读:
eks 包技术文档 (Tidy spatial
kernel density estimates)。# ==============================================================================
# 4.3 连续表面重构:核密度估计 (Kernel Density Estimation)
# ==============================================================================
# 1. 坐标分离:提取 sf 对象中的 X, Y 坐标供 KDE 算法底层计算使用
weibo_coords <- weibo_minhang %>%
mutate(
lon = st_coordinates(geometry)[, 1],
lat = st_coordinates(geometry)[, 2]
) %>%
st_drop_geometry() # 剥离几何属性,转化为纯数据框以加速运算
# 2. KDE 热力图分布可视化
ggplot() +
# 2.1 地理语境层:载入高德瓦片底图 (透明度调低,作为暗底)
annotation_map_tile(type = amap_xyz, zoom = 13, alpha = 0.3) +
# 2.2 核心表面层:KDE 核密度等值面绘制
stat_density_2d(
data = weibo_coords,
aes(
x = lon, y = lat,
fill = after_stat(level), # 根据密度值映射填充色
alpha = after_stat(level) # 根据密度值映射透明度 (低密度更透明,融入底图)
),
geom = "polygon", # 渲染为多边形等值面
bins = 20 # 划分 20 个密度层级,保证平滑过渡
) +
# 2.3 色彩与透明度映射
# 使用学术界经典的热力色系 Inferno (黑-紫-橙-黄)
scale_fill_viridis_c(option = "inferno", name = "KDE Level") +
# 屏蔽透明度的图例,并设定透明度域 (核心区不透明,边缘极透明)
scale_alpha_continuous(range = c(0.1, 0.8), guide = "none") +
# 2.4 边界约束层:叠加黑色粗线边界,强化行政区划的视觉约束感
geom_sf(data = minhang_boundary, fill = NA, colour = "black", linewidth = 0.8, alpha = 0.8) +
# 2.5 空间参考组件:提取闵行区边界框 (BBox) 锁定地图视野,防止 KDE 边缘溢出导致视野拉远
coord_sf(
crs = 4326,
xlim = st_bbox(minhang_boundary)[c("xmin", "xmax")],
ylim = st_bbox(minhang_boundary)[c("ymin", "ymax")],
expand = TRUE
) +
annotation_scale(
location = "bl", width_hint = 0.25, style = "ticks", text_col = "grey20"
) +
annotation_north_arrow(
location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(text_col = "grey20", line_col = "grey40")
) +
# 2.6 学术排版主题配置
theme_bw() +
theme(
legend.position = "right",
legend.title = element_text(face = "bold", size = 9),
legend.text = element_text(size = 8),
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(colour = "grey30", hjust = 0.5),
panel.grid = element_blank(),
axis.text = element_text(size = 8, colour = "grey40"),
axis.title = element_blank()
) +
labs(
title = "Kernel Density Estimation of Digital Vitality (Weibo)",
subtitle = "Minhang District, Shanghai | Bandwidth: Automatic",
caption = "Basemap: Amap | Coordinate System: GCJ-02 mapped to WGS84"
)阶段性成果分析
通过核密度估计(KDE),本节将离散的微观活动锚点重构为连续的活力强度表面。可视化结果清晰刻画了闵行区内部的数字活力层级梯度,深橙色与亮黄色的等值面标识了极高强度的活动集聚核心。这一平滑表面不仅消除了海量散点重叠造成的视觉盲区,更直观验证了该区域多中心的空间分布结构。
当前结果评估
当前的 KDE 热力图虽然呈现了活力的宏观聚集态势,但依然停留在视觉定性表达层面,缺乏可用于微观统计测度的物理边界。后续分析将聚焦于以下方向:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
前一小节基于绘图渲染机制(stat_density_2d)实现了连续热力表面的视觉表达。
本节将采用空间统计算法计算核密度矩阵,并通过设定统计阈值,将密度表面转化为可供空间度量的实体多边形边界(Area of Interest,
AOI)。该过程主要包含以下三个步骤:
kde2d()
算法在投影坐标下生成二维核密度矩阵,利用
stars 包将其重构为带有空间参考的栅格数据(Raster),并进一步转化为矢量等值面(Vector Polygons)。st_union)生成 AOI
多边形要素,并将其边界叠加于原始热力图上进行空间范围核对。MASS::kde2d 能否直接在 WGS84 坐标系下运行?
从纯算法运算角度,kde2d 能够处理任何数值型 X/Y
坐标输入;但从空间统计学的严谨性出发,执行核密度估计前应将数据转换至局部投影坐标系(如本节使用的 UTM Zone 51N)。主要原因如下:
# ==============================================================================
# 4.4 AOI 极核提取与边界可视化 (AOI Extraction & Visualisation)
# ==============================================================================
# ------------------------------------------------------------------------------
# 第一步:坐标投影转换 (Projected Coordinate System)
# ------------------------------------------------------------------------------
# 强制转换为上海本地的 UTM Zone 51N (EPSG:32651),单位为米。
# 教学提示:这是保障后续 KDE 密度估算和面积计算绝对精准的物理前提。
target_crs <- 32651
minhang_proj <- minhang_boundary %>% st_transform(target_crs)
weibo_proj <- weibo_minhang %>% st_transform(target_crs)
# ------------------------------------------------------------------------------
# 第二步:核密度等值面生成与 AOI 动态提取
# ------------------------------------------------------------------------------
# 1. 提取投影后的 XY 坐标 (以米为单位)
coords <- st_coordinates(weibo_proj)
# 2. 运行二维核密度估计 (n = 150 决定了输出栅格的分辨率与平滑度)
kde_res <- kde2d(coords[,1], coords[,2], n = 150)
# 3. 手动构建 stars 栅格对象 (彻底规避 st_as_stars 自动解析 List 时的报错)
# 直接将核心的密度矩阵 z 放入,并明确命名为 density
kde_stars <- st_as_stars(density = kde_res$z)
# 手动将 X 和 Y 的坐标向量绑定到栅格的维度上
kde_stars <- st_set_dimensions(kde_stars, 1, values = kde_res$x, names = "x")
kde_stars <- st_set_dimensions(kde_stars, 2, values = kde_res$y, names = "y")
# 挂载本地投影坐标系
kde_stars <- st_set_crs(kde_stars, target_crs)
# 4. 将 stars 栅格转化为 sf 矢量等值面 (Raster to Vector Conversion)
kde_sf <- st_as_sf(kde_stars, as_points = FALSE, merge = TRUE)
# ==============================================================================
#【关键调节参数】:AOI 阈值设定 (Thresholding)
# ==============================================================================
# 0.95 代表我们只提取密度值排名前 5% (1 - 0.95) 的区域作为“核心活力极核”
aoi_threshold_pct <- 0.95
# 计算对应的绝对密度阈值
threshold_val <- quantile(kde_sf$density, aoi_threshold_pct)
# 5. 提取 >= 阈值的多边形,并融合 (Union) 为完整的 AOI 边界
aoi_polygon <- kde_sf %>%
filter(density >= threshold_val) %>%
st_union() %>%
st_make_valid()
# ------------------------------------------------------------------------------
# 第三步:AOI 提取结果的核对与可视化 (Overlay Mapping)
# ------------------------------------------------------------------------------
# 提取未投影的 WGS84 坐标系用于底层热力图的对齐渲染
weibo_coords <- weibo_minhang %>%
mutate(lon = st_coordinates(geometry)[, 1], lat = st_coordinates(geometry)[, 2]) %>%
st_drop_geometry()
ggplot() +
# 1. 地理语境层:载入底图
annotation_map_tile(type = amap_xyz, zoom = 13, alpha = 0.5) +
# 2. 连续表面层:底层 KDE 热力图 (作为参照背景)
stat_density_2d(
data = weibo_coords,
aes(x = lon, y = lat, fill = after_stat(level), alpha = after_stat(level)),
geom = "polygon", bins = 15
) +
scale_fill_viridis_c(option = "inferno", name = "Density Level") +
scale_alpha_continuous(range = c(0.1, 0.8), guide = "none") +
# 3. 边界约束层:闵行区外轮廓 (采用 UK spelling: colour)
geom_sf(data = minhang_boundary, fill = NA, colour = "black", linewidth = 0.8) +
# 4. AOI 核心高亮层:叠加刚提取的多边形边界
# 动态转回 WGS84 (4326) 以匹配底图渲染
geom_sf(data = st_transform(aoi_polygon, 4326),
aes(colour = paste0("Vitality AOI (Top ", (1-aoi_threshold_pct)*100, "%)")), # (采用 UK spelling: colour)
fill = NA, linewidth = 1.2, linetype = "dashed") +
scale_colour_manual(values = "#00FF00", name = "Extracted Boundary") + # 荧光绿极高亮对比
# 5. 地图参考组件与视野锁定
coord_sf(
crs = 4326,
xlim = st_bbox(minhang_boundary)[c("xmin", "xmax")],
ylim = st_bbox(minhang_boundary)[c("ymin", "ymax")],
expand = TRUE
) +
annotation_scale(
location = "bl", width_hint = 0.25, style = "ticks", text_col = "grey20" # (采用 UK spelling: grey)
) +
annotation_north_arrow(
location = "br", which_north = "true",
style = north_arrow_fancy_orienteering(text_col = "grey20", line_col = "grey40") # (采用 UK spelling: grey)
) +
# 6. 学术主题排版
theme_bw() +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(colour = "grey30", hjust = 0.5), # (采用 UK spelling: colour/grey)
panel.grid = element_blank(),
axis.title = element_blank()
) +
labs(
title = "AOI Extraction based on KDE Surface",
subtitle = "Verifying the spatial alignment of the computed threshold boundary",
caption = "Dashed Green Line: Extracted AOI | Background: KDE Surface"
)阶段性成果分析
通过设定 Top 5% 的密度阈值,算法实现了从连续热力表面(栅格数据)向明确空间边界(矢量多边形)的特征提取。
可视化识别结果显示,该阈值准确界定了研究区内的三大核心活力极核:虹桥枢纽、莘庄-七宝复合区以及紫竹高新区。在空间形态上,三者呈现出差异化特征:虹桥枢纽虽然覆盖面积相对较小,但承载了全区最高的密度峰值;莘庄与七宝则因空间邻近性与功能的溢出效应呈现连片分布态势,构成了区内规模最大的连续高活力地带。
当前结果评估
至此,本节构建了基于二元空间的分析框架,将研究区细分为AOI(核心活力极核区)与非 AOI(一般覆盖区)。该空间划分确立了后续差异化统计分析的几何基准。
下一阶段将引入微观可达性评价维度。基于上述两类空间划分,计算各样本点(微博观测数据)至最近公共交通节点(轨道交通、公交站点)的欧氏距离(Euclidean distance)。通过该空间测度,旨在量化并对比城市基础设施配置的空间公平性特征及其在不同活力层级区域间的效能差异。
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
基于前述识别的核心活力极核(AOI),本节引入城市公共交通 POI 空间坐标,通过测算观测点至最近交通设施的空间欧氏距离,定量剖析 AOI 与非 AOI 区域在交通可达性配置上的特征差异。该量化流程分为以下四个标准化步骤:
空间坐标系重投影:
将轨道交通与公交站点数据统一转换为局部投影坐标系(如
UTM Zone 51N)。此步骤旨在确保空间距离计算的物理单位符合标准米制,避免地理坐标系下度数单位引起的偏差。
空间属性关联与分组:
运用空间相交运算(st_intersects)识别各观测点与 AOI
多边形的拓扑包含关系。依据该关系将样本划分为高活力极核区(AOI)与一般覆盖区(Non-AOI)两个对比组。
最近邻特征检索与测度:
调用
st_nearest_feature()
算子检索各观测点至最近交通节点的索引,并计算对应的直线距离。在执行过程中启用逐行匹配模式(by_element = TRUE),以优化计算效率并规避全量距离矩阵造成的内存占用风险。
复合统计特征可视化:
在完成长尾极值(如 Top 5% 离群值)截断后,构建融合抖动散点、小提琴图与箱线图的复合统计图表。
通过多图层叠加,系统呈现两类空间在交通可达性分布上的概率密度轮廓与核心统计分位特征。
# ==============================================================================
# 4.5 空间可达性量化:AOI 划分与最近邻距离计算
# ==============================================================================
# ------------------------------------------------------------------------------
# 1. 交通 POI 投影统一 (Coordinate Projection)
# ------------------------------------------------------------------------------
# 将前期已加载的地铁站和公交站统一转换为本地投影坐标系 (UTM Zone 51N, EPSG:32651)
# 教学提示:必须执行此步,以确保后续空间距离计算的物理单位为“米” (Metres)
subway_proj <- poi_subway %>% st_transform(target_crs)
bus_proj <- poi_bus %>% st_transform(target_crs)
# ------------------------------------------------------------------------------
# 2. 空间拓扑打标 (Point-in-Polygon Tagging)
# ------------------------------------------------------------------------------
# 利用 st_intersects 判断微博点是否落在 AOI (活力极核) 边界内
weibo_proj <- weibo_proj %>%
mutate(
# lengths() > 0 表示相交。动态引用上方定义的极核阈值
Zone = ifelse(
lengths(st_intersects(geometry, aoi_polygon)) > 0,
paste0("AOI (Top ", (1-aoi_threshold_pct)*100, "% Vitality)"),
"Non-AOI (General)"
)
)
# 打印两类点的数量对比,供授课时参考
cat("AOI 内微博点数:", sum(weibo_proj$Zone != "Non-AOI (General)"),
"| 非 AOI 点数:", sum(weibo_proj$Zone == "Non-AOI (General)"), "\n")
# ------------------------------------------------------------------------------
# 3. 极速计算最近邻距离 (Nearest Neighbour Distance)
# ------------------------------------------------------------------------------
# 教学提示:st_nearest_feature 能极其高效地找到距离每个微博点最近的交通站点索引
weibo_proj <- weibo_proj %>%
mutate(
# 计算到最近地铁站的直线距离 (单位:米)
dist_to_subway = as.numeric(st_distance(
geometry,
subway_proj[st_nearest_feature(geometry, subway_proj), ],
by_element = TRUE # 必须保留:强制逐元素计算,避免生成庞大的全量距离矩阵导致内存崩溃
)),
# 计算到最近公交站的直线距离 (单位:米)
dist_to_bus = as.numeric(st_distance(
geometry,
bus_proj[st_nearest_feature(geometry, bus_proj), ],
by_element = TRUE
))
)
# ==============================================================================
# 4.6 统计可视化:空间可达性复合图 (Violin + Jitter + Boxplot)
# ==============================================================================
# ------------------------------------------------------------------------------
# 1) 数据结构转换 (Wide to Long)
# ------------------------------------------------------------------------------
weibo_dist_long <- weibo_proj %>%
st_drop_geometry() %>% # 剥离空间属性,转为纯表格以加速 ggplot 渲染
dplyr::select(Zone, dist_to_subway, dist_to_bus) %>%
pivot_longer(
cols = c(dist_to_subway, dist_to_bus),
names_to = "Facility_Type",
values_to = "Distance_m"
) %>%
mutate(
# 优化分面标签的显示文本
Facility_Type = recode(Facility_Type,
"dist_to_subway" = "Nearest Subway Station",
"dist_to_bus" = "Nearest Bus Stop")
)
# ------------------------------------------------------------------------------
# 2) 数据清洗与长尾截断 (极值处理)
# ------------------------------------------------------------------------------
plot_data_refined <- weibo_dist_long %>%
# 按设施类型分组,截断距离分布的头部 5% 极端异常值 (聚焦 95% 的核心大众群体)
group_by(Facility_Type) %>%
filter(Distance_m <= quantile(Distance_m, 0.95)) %>%
ungroup() %>%
# 确保因子顺序,让高活力区 (AOI) 稳居图例与 X 轴的左侧首位
mutate(Zone = factor(Zone, levels = c(paste0("AOI (Top ", (1-aoi_threshold_pct)*100, "% Vitality)"),
"Non-AOI (General)")))
# ------------------------------------------------------------------------------
# 3) 绘图:多图层叠加呈现数据全貌
# ------------------------------------------------------------------------------
ggplot(
data = plot_data_refined,
mapping = aes(
x = Zone,
y = Distance_m,
fill = Zone, # 内部填充色映射
colour = Zone # 外部轮廓色映射
)
) +
# 图层 1:底层抖动散点 (极低透明度,展示真实数据量级与离散感)
geom_jitter(
width = 0.05, # X 轴适度抖动错开重叠
height = 0, # Y 轴绝对不抖动以保障数值真实性
alpha = 0.05, # 极低透明度作为背景肌理
size = 0.1,
colour = "grey40" # 使用中性灰避免与主色调冲突
) +
# 图层 2:中层小提琴图 (展示概率密度轮廓)
geom_violin(
alpha = 0.30, # 半透明,透出底层的散点
trim = FALSE, # 不裁剪尾部,保留完整的密度曲线分布
linewidth = 0.6 # 强化边缘轮廓线
) +
# 图层 3:顶层极窄箱线图 (展示中位数与四分位距核心统计特征)
geom_boxplot(
width = 0.15, # 极其收敛的宽度,嵌入小提琴内部
alpha = 0.60, # 较高不透明度压住阵脚
colour = "black", # 纯黑轮廓增加对比度
outlier.shape = NA # 屏蔽原本箱线图的异常点
) +
# 分面:地铁与公交独立展示,释放各自的 Y 轴自适应缩放空间
facet_wrap(~ Facility_Type, scales = "free_y") +
# 采用高对比度的经典 Set2 色盘
scale_fill_brewer(palette = "Set2") +
scale_colour_brewer(palette = "Set2") +
# 标题与标签体系
labs(
title = "Transit Accessibility Profiling of Digital Vitality Zones",
subtitle = "Violin density, jittered points & internal boxplot (Top 95% core distances)",
x = NULL,
y = "Straight-line Distance to Nearest Node (Metres)" #
) +
# 排版主题
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0),
plot.subtitle = element_text(size = 10, colour = "grey50", face = "italic", margin = margin(b = 15)),
# Y轴文字加黑加粗,显著提升数字刻度的可读性
axis.title.y = element_text(face = "bold", size = 11, margin = margin(r = 10)),
axis.text.y = element_text(size = 10, colour = "black", face = "bold"),
axis.text.x = element_text(face = "bold", size = 11, colour = "black"),
# 优化分面标签的底色与边框,增强学术感
strip.background = element_rect(fill = "#f0f0f0", colour = "grey80", linewidth = 0.5),
strip.text = element_text(face = "bold", size = 12, margin = margin(t = 6, b = 6)),
# 隐藏冗余图例
legend.position = "none",
# 增加面板边框,清晰界定子图范围
panel.border = element_rect(colour = "grey80", fill = NA, linewidth = 0.5),
panel.grid.minor = element_blank()
)可达性规律发现
复合统计图表直观揭示了城市数字活力与公共交通可达性之间的空间耦合关系。整体而言,公共交通基础设施对微观数字活力的集聚具有显著的空间锚定作用,其中大容量、高等级的轨道交通节点(地铁)对高活力极核的支撑与塑造效应尤为突出。
从绝对距离分布来看,由于常规公交系统的站点密度天然高于轨道交通,各类观测点至最近公交站的物理直线距离均显著短于最近地铁站。若进一步对比二元空间类别,高活力极核(AOI)的交通节点可达性全面优于一般覆盖区(Non-AOI),且在不同设施类型上呈现出显著的分化特征:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
重要
本章将对前述专题研究 2进行复盘。该示例以带地理坐标的社交媒体点作为城市数字活动的空间代理,并以地铁站与公交站 POI刻画公共交通服务供给条件。整体流程覆盖了从点数据清洗、空间约束、热点识别到可达性对比的完整探索性空间分析路径,适用于多源点数据的快速诊断与证据呈现。
进阶阅读
为什么可用:
带地理坐标的社交媒体数据记录了用户在特定时间与地点的线上活动足迹,具备较高的时空分辨率与持续更新特征。因而它常被用于刻画城市活动的时段节律、热点结构与功能差异,并作为传统统计与调查数据之外的补充证据,用于理解城市空间的细粒度“活动纹理”。
需要警惕的偏差:
作为城市活力的代理指标,它可能受到用户群体结构、平台渗透率、发帖动机、空间覆盖不均、定位误差以及机器人/营销账号等因素影响。解释结果时应明确:它更接近“可观测的数字活动强度”,不等同于人口规模、出行总量或完整的线下活动水平。
推荐文献(DOI):
Chen, M., Liu, Y., et
al. (2024). Vivid London: Assessing the resilience of urban vibrancy
during the COVID-19 pandemic using social media data.
Sustainable Cities and Society. https://doi.org/10.1016/j.scs.2024.105823
Wu, C.,
Ye, X., Ren, F., & Du, Q. (2018). Check-in behaviour and
spatio-temporal vibrancy: An exploratory analysis in Shenzhen,
China. Cities. https://doi.org/10.1016/j.cities.2018.01.017
Wang,
X., Zhang, Y., Yu, D., Qi, J., & Li, S. (2022). Investigating
the spatiotemporal pattern of urban vibrancy and its determinants:
Spatial big data analyses in Beijing, China. Land Use
Policy. https://doi.org/10.1016/j.landusepol.2022.106162
回顾专题研究 2,分析目标是识别上海市闵行区城市数字活动的热点空间结构,并对比热点区与非热点区在公共交通可达性上的差异。核心工作流可概括为以下四步:
研究区界定与多源数据载入:
读取上海行政边界并提取闵行区作为研究范围;加载微博点数据(表格坐标)与公交/地铁 POI(空间点),统一到同一坐标参考系,完成空间落位与基础制图核对。
空间约束与点数据预处理:
通过
st_as_sf() 将微博坐标转为空间点对象,并用 Point-in-Polygon
裁剪将样本约束到闵行区边界内,获得研究区有效点集与基础分布图。
热点强度面构建与 AOI 提取:
使用核密度估计(KDE)将离散点转换为连续强度表面;随后在投影坐标系下计算密度矩阵,并以分位数阈值(Top 5%)提取高值区域,构建可度量的活力 AOI 多边形(Area of
Interest)。
可达性量化与分组对比:
基于 AOI 与非 AOI
的二元分组,用最近邻方法计算微博点到最近公交站与地铁站的直线距离,借助复合分布图(小提琴 + 箱线 +
抖动点)对比两类区域的距离差异,用于解释热点与交通设施的空间耦合。
重要
从模式识别到机制解释
本章流程能够清晰呈现热点与可达性差异,但关键结论依赖若干数据假设与参数选择。下面的问题用于在复现实操结果时保持批判性视角:
社交媒体点的代表性与偏差:
微博签到/发布点反映的是平台用户的可观测行为。不同年龄、职业与居住群体的使用强度差异,可能导致“活力高”更多对应“更愿意发帖的人群”与“更易被记录的场景”。若用于讨论空间公平性,需明确其指标属性与适用边界。
时间窗口与稳定性:
若样本跨年份或跨季节汇总,热点可能是“长期结构”,也可能是“阶段性事件与节假日效应”的叠加结果。更稳健的做法是按月/季分段重复
KDE 与 AOI 提取,比较热点位置与强度是否稳定。
AOI
阈值设定的可解释性:
Top 5%
是便于教学的经验阈值,但它隐含了“热点面积占比固定”的假设。可考虑用多阈值(Top
1/5/10%)对比 AOI
的空间形态,或基于绝对密度值与业务含义设定阈值。
KDE
的带宽、分辨率与边界效应:
KDE
的带宽与网格分辨率决定了热点的“平滑尺度”。带宽偏大可能合并多个局部中心,偏小则会产生破碎斑块;行政边界附近还可能出现边界截断效应。教学示例可用自动带宽,但研究场景应报告带宽设定依据,并做敏感性分析
常见。
可达性度量的距离定义:后续研究
直线距离易计算,适合快速对比,但不等同于真实步行或换乘成本。若用于交通公平性讨论,建议进一步引入路网距离、步行时间或多模式出行时间,并区分站点等级与线路服务强度。
从空间耦合走向机制检验:后续研究
AOI
更接近“活动结果”,交通站点更接近“供给条件”。两者的相关并不等于因果。若要解释机制,可引入建成环境与人口结构变量(用地、就业、教育资源、居住密度等),采用回归或匹配方法控制混杂因素,并检验不同子区域的异质性。
进阶阅读
什么是敏感性分析:
敏感性分析(Sensitivity
Analysis)指在不改变数据与总体方法框架的前提下,系统性调整关键参数,观察结果是否稳定。它用于回答一个核心问题:你的主要结论是否“依赖某个参数取值”。
为什么要做:
在空间分析中,许多关键结果来自参数设定(如 KDE
带宽、网格分辨率、AOI
阈值)。若结论只在某个参数下成立,则其可解释性与可复现性会下降。敏感性分析的目的不是寻找“唯一正确的参数”,而是评估结论在合理参数区间内是否方向一致、空间位置相近、差异幅度可控。
怎么做(以本节 KDE
为例):
可用“三步法”组织一个最小可行的流程:
定义候选参数集合:
对带宽(bandwidth)设定一组候选值,例如:\(h \in \{300m, 500m, 800m, 1200m\}\)(示意)。
重复计算并生成可比结果:
在每个带宽下重复:KDE 表面 → AOI 提取(保持同一阈值,如 Top 5%) → 输出 AOI
多边形。
用一致指标比较稳定性:
如何选取带宽(两条主线):
什么时候可以不做:
在部分科研场景中,若关键参数在领域内已有较一致的理论含义或经验共识(并能提供明确来源与设定理由),可不展开完整敏感性分析,而改为:报告参数依据
+ 少量对照(例如 2–3
个代表性取值),以满足可解释性与可复现性的最低要求。
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)
实战目标
本节练习将使用咖啡店兴趣点数据 (POI)与上海市闵行区行政区数据,结合 dbscan
算法开展基于密度的空间聚类分析,并完成结果的地图表达。DBSCAN
由 Ester 等人在 1996
年提出,属于经典的密度聚类方法;其后续讨论与参数使用建议可参考 Schubert
等人的综述,R 中的高效实现则可见 Hahsler 等人的 dbscan
包论文。
数据来源:
下载地址:https://dawn-ecnu.github.io/data/
研究任务:
任务 |
上海市闵行区咖啡店空间聚类与 AOI 识别:基于
DBSCAN
算法识别闵行区咖啡店的高密度集聚区,并进一步利用凹包(Concave Hull) 方法生成各聚类簇对应的商圈 AOI
边界,从而刻画咖啡商业空间的集聚格局与覆盖范围。
重要 常用
DBSCAN (Density-Based Spatial
Clustering of Applications with Noise) 是一种基于局部密度的聚类方法。其核心思路并不是预先指定聚类个数,而是通过邻域密度判断哪些点能够形成稳定簇、哪些点应被视为噪声。相较于传统的
k-means,DBSCAN 更适合处理不规则形状的空间聚类,并能够同时识别离散噪声点。
minPts 个点 (含自身)
的点,是聚类扩展的起点。minPts,但位于某个核心点的邻域内,因此仍归属于某个聚类。DBSCAN 空间对象类别判定示意图
参考文献与学习链接
Ester, M., Kriegel, H.-P., Sander, J., & Xu, X. (1996). A density-based algorithm for discovering clusters in large spatial databases with noise. KDD. DOI / 链接
Hahsler, M., Piekenbrock, M., & Doran, D. (2019). dbscan: Fast Density-Based Clustering with R. Journal of Statistical Software, 91(1), 1–30. DOI / 链接
dbscan 包 CRAN 页面: 点击访问
dbscan 官方 vignette:Fast Density-based
Clustering (DBSCAN and OPTICS) 点击访问
dbscan 官方 vignette:HDBSCAN with the dbscan
package 点击访问
这是一个“照着做”的练习:先复现图形,再逐步理解各步骤背后的分析逻辑。
dbscan 包提供了基于局部密度的空间聚类算法实现,可用于识别点数据中的高密度集聚区及离散噪声点。在开始练习前,请先完成该包的安装。
# ============================================================
# 1. 环境准备与依赖包加载
# ============================================================
library(dbscan) # 密度聚类算法
library(sf) # 空间数据读写与空间操作
library(tidyverse) # 数据整理与可视化
library(ggspatial) # 比例尺、指北针与瓦片底图
# ============================================================
# 2. 数据读取与研究范围裁取
# ============================================================
# 读取上海市边界,并统一转换为 WGS84 坐标系
shanghai_boundary <- st_read("data/shanghai_boundary.geojson", quiet = TRUE) %>%
st_transform(4326)
# 提取闵行区行政边界
minhang_boundary <- shanghai_boundary %>%
filter(县代码 == "310112")
# 读取咖啡店 POI,并统一转换为 WGS84 坐标系
poi_coffee <- st_read(
"data/咖啡厅.geojson",
options = "ENCODING=UTF-8",
quiet = TRUE
) %>%
st_transform(4326)
# 空间裁取:仅保留位于闵行区范围内的咖啡店点位
minhang_cafe <- st_intersection(poi_coffee, minhang_boundary)
# ============================================================
# 3. DBSCAN 聚类计算
# ============================================================
# DBSCAN 的距离计算应在平面投影下完成,因此先转换为 UTM 51N
cafe_for_clustering <- minhang_cafe %>%
st_transform(32651)
# 提取点坐标并转换为数值矩阵
coords <- st_coordinates(cafe_for_clustering)
# 执行 DBSCAN 聚类
# eps = 500 表示邻域半径为 500 米
# minPts = 10 表示形成局部高密度区域至少需要 10 个点
db_res <- dbscan(coords, eps = 500, minPts = 10)
# 将聚类结果写回原始 sf 对象
# cluster_id = 0 表示噪声点,其余整数表示不同聚类
minhang_cafe <- minhang_cafe %>%
mutate(
cluster_id = db_res$cluster,
cluster_label = if_else(
cluster_id == 0,
"Noise",
paste0("Cluster ", cluster_id)
)
) %>%
# 按聚类编号排序,便于后续绘图时控制图层显示顺序
arrange(cluster_id)
# ============================================================
# 4. 图例映射方案:颜色、形状与大小
# ============================================================
# 提取真实聚类编号(不含噪声点)
cluster_ids <- sort(unique(minhang_cafe$cluster_id[minhang_cafe$cluster_id != 0]))
# 为各聚类动态生成离散色盘
cluster_cols <- grDevices::hcl.colors(length(cluster_ids), palette = "Dark 3")
names(cluster_cols) <- paste0("Cluster ", cluster_ids)
# 设定噪声点颜色,并合并为统一的颜色映射表
plot_cols <- c("Noise" = "grey20", cluster_cols)
# 设定形状映射:噪声点为十字,聚类点为实心圆
plot_shapes <- c("Noise" = 3, setNames(rep(16, length(cluster_ids)), names(cluster_cols)))
# 设定大小映射:噪声点较小,聚类点相对更突出
plot_sizes <- c("Noise" = 0.8, setNames(rep(2.5, length(cluster_ids)), names(cluster_cols)))
# ============================================================
# 5. 可视化:闵行区咖啡店 DBSCAN 聚类结果
# ============================================================
# 高德公开 XYZ 瓦片底图
amap_xyz <- "http://wprd01.is.autonavi.com/appmaptile?x=${x}&y=${y}&z=${z}&lang=zh_cn&size=1&scl=1&style=7&ext=.png"
ggplot() +
# 5.1 底图图层
annotation_map_tile(type = amap_xyz, zoom = 12, alpha = 0.35) +
# 5.2 行政边界图层
geom_sf(
data = minhang_boundary,
aes(linetype = "Minhang Boundary"),
fill = NA,
colour = "darkred",
linewidth = 0.8,
alpha = 0.8
) +
# 5.3 点要素图层
# 同时映射颜色、形状与大小,以保证图面与图例表达一致
geom_sf(
data = minhang_cafe,
aes(color = cluster_label, shape = cluster_label, size = cluster_label),
alpha = 0.85
) +
# 5.4 制图要素:比例尺与指北针
annotation_scale(
location = "bl",
width_hint = 0.25,
style = "ticks",
text_cex = 0.6,
text_col = "grey20"
) +
annotation_north_arrow(
location = "br",
which_north = "true",
height = unit(0.8, "cm"),
width = unit(0.8, "cm"),
pad_x = unit(0.1, "cm"),
pad_y = unit(0.1, "cm"),
style = north_arrow_fancy_orienteering(
fill = c("black", "white"),
line_col = "grey20"
)
) +
# 5.5 图例与标度设置
scale_linetype_manual(
name = "Study Area",
values = c("Minhang Boundary" = "solid")
) +
scale_color_manual(
name = "DBSCAN Result",
values = plot_cols
) +
scale_shape_manual(
name = "DBSCAN Result",
values = plot_shapes
) +
scale_size_manual(
name = "DBSCAN Result",
values = plot_sizes
) +
# 调整图例顺序,并覆盖边界图例的默认显示样式
guides(
linetype = guide_legend(
override.aes = list(color = "darkred", linewidth = 0.8),
order = 1
),
color = guide_legend(order = 2),
shape = guide_legend(order = 2),
size = guide_legend(order = 2)
) +
# 5.6 版式设置
theme_bw() +
theme(
legend.position = "right",
legend.title = element_text(size = 10, face = "bold"),
legend.text = element_text(size = 9),
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(color = "grey40", hjust = 0.5, size = 10),
panel.grid.major = element_line(colour = "grey90", linetype = "dashed")
) +
# 5.7 图题与附注
labs(
title = "Coffee Shop Clusters in Minhang District, Shanghai",
subtitle = "DBSCAN results with eps = 500 m and minPts = 10",
caption = "Coordinate System: WGS84 (EPSG:4326) | Basemap: Amap"
)可视化结果分析
基于 DBSCAN 的空间密度分析结果 (参数设定为 eps = 500
米、minPts = 10),闵行区咖啡店的空间分布呈现出较明显的非均衡性与多中心集聚特征。在该参数条件下,研究范围内共识别出
9 个主要聚类簇 (Cluster
1–9),整体格局可概括为“北部集聚较强,中部存在次级中心,南部相对分散”。
北部高密度集聚区:
闵行区北部识别出多个规模较大、密度较高的咖啡聚类簇,主要分布于靠近长宁、徐汇交界地带及虹桥枢纽周边区域。以
Cluster 9、Cluster 5 及
Cluster 2–3
为代表的聚类簇,空间上较为集中,说明该区域已形成较明显的咖啡商业集聚格局。这一分布与交通枢纽、商务办公及高强度消费活动的空间组织方式具有一定一致性。
中部次级集聚区:
在闵行区中部 (如莘庄等板块),可观察到若干中等规模的聚类簇,例如
Cluster 6 与 Cluster
7。相较于北部核心集聚区,这些聚类的规模与密度略低,但仍表现出稳定的局部集聚特征,说明咖啡消费已不仅局限于交通与商务核心区,也在区域副中心与成熟居住区中形成一定规模的节点式分布。
南部低密度分散区:
闵行区南部及东南部较大范围内,图中主要表现为灰黑色的噪声点
(Noise)。这表明相关区域虽然存在咖啡店分布,但其空间密度尚未达到当前
DBSCAN 参数设定下的聚类阈值,即在 500
米邻域范围内未形成至少 10
个点的局部高密度结构。由此可见,该区域目前更接近离散分布状态,尚未形成较稳定的咖啡商业集聚区。
从点云到 AOI
前一步的 DBSCAN
结果已经帮助识别出咖啡店的高密度聚类簇,但这些结果仍以离散点云的形式呈现。点状表达有助于观察聚类中心与局部密度,却较难直观界定各聚类簇在空间上的实际覆盖范围,也不利于将其进一步理解为具有连续边界的商业活动区。
因此,本步骤进一步将已识别的聚类点转化为面状的 AOI
(Area of
Interest)。具体做法是:仅保留非噪声点,并按聚类标签分别合并为
MULTIPOINT 对象,再利用凹包算法
(Concave
Hull)生成更贴近点云外缘的边界。与简单的凸包相比,凹包能够更好保留聚类簇的不规则形态,从而使最终结果更接近现实空间中咖啡商业集聚区的轮廓
(参考代码之后的延伸阅读)。
# ============================================================
# 6. 生成咖啡商圈 AOI:基于凹包(Concave Hull)算法
# ============================================================
# AOI(Area of Interest)在此用于将离散点云转化为具有连续边界的空间区域,
# 从而更直观地表达各咖啡聚类簇的实际覆盖范围。
aoi_polygons <- minhang_cafe %>%
# 仅使用已形成聚类的点,噪声点不参与 AOI 边界生成
filter(cluster_id != 0) %>%
# 按聚类标签分组,为每个聚类分别生成对应的 AOI
group_by(cluster_label) %>%
# 将同一聚类中的所有点合并为一个 MULTIPOINT 几何对象
summarise(geometry = st_union(geometry)) %>%
# 基于凹包算法生成聚类边界
# ratio 取值介于 0 与 1 之间:
# 值越小,边界越贴近点云形态;值越接近 1,结果越接近凸包
# allow_holes = FALSE 表示不保留内部空洞,以形成连续完整的商圈范围
st_concave_hull(ratio = 0.8, allow_holes = FALSE)
# ============================================================
# 7. 可视化:闵行区咖啡商圈 AOI 边界
# ============================================================
ggplot() +
# 7.1 底图图层
annotation_map_tile(type = amap_xyz, zoom = 12, alpha = 0.35) +
# 7.2 行政边界图层
geom_sf(
data = minhang_boundary,
aes(linetype = "Minhang Boundary"),
fill = NA,
colour = "darkred",
linewidth = 0.8,
alpha = 0.8
) +
# 7.3 商圈 AOI 多边形图层
# 使用填充色与边框色同时区分不同聚类簇
geom_sf(
data = aoi_polygons,
aes(fill = cluster_label, color = cluster_label),
alpha = 0.35, # 保持一定透明度,便于识别底图信息
linewidth = 0.6 # AOI 边界线宽
) +
# 7.4 噪声点图层
# 将未被聚类识别的点保留在图中,用作空间对照
geom_sf(
data = minhang_cafe %>% filter(cluster_id == 0),
aes(shape = "Noise"),
color = "grey30",
size = 0.8,
alpha = 0.6
) +
# 7.5 制图要素:比例尺与指北针
annotation_scale(
location = "bl",
width_hint = 0.25,
style = "ticks",
text_cex = 0.6,
text_col = "grey20"
) +
annotation_north_arrow(
location = "br",
which_north = "true",
height = unit(0.8, "cm"),
width = unit(0.8, "cm"),
pad_x = unit(0.1, "cm"),
pad_y = unit(0.1, "cm"),
style = north_arrow_fancy_orienteering(
fill = c("black", "white"),
line_col = "grey20"
)
) +
# 7.6 图例与标度设置
scale_linetype_manual(
name = "Study Area",
values = c("Minhang Boundary" = "solid")
) +
scale_fill_manual(
name = "Coffee AOI Clusters",
values = cluster_cols
) +
scale_color_manual(
name = "Coffee AOI Clusters",
values = cluster_cols
) +
scale_shape_manual(
name = "Unclustered",
values = c("Noise" = 3)
) +
# 调整图例顺序,并统一图例显示样式
guides(
linetype = guide_legend(
override.aes = list(color = "darkred", linewidth = 0.8),
order = 1
),
fill = guide_legend(
order = 2,
override.aes = list(alpha = 0.6)
),
color = guide_legend(order = 2),
shape = guide_legend(order = 3)
) +
# 7.7 版式设置
theme_bw() +
theme(
legend.position = "right",
legend.title = element_text(size = 10, face = "bold"),
legend.text = element_text(size = 9),
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(color = "grey40", hjust = 0.5, size = 10),
panel.grid.major = element_line(colour = "grey90", linetype = "dashed")
) +
# 7.8 图题与附注
labs(
title = "Coffee Shop Commercial AOIs in Minhang District",
subtitle = "AOI boundaries generated via the concave hull algorithm (ratio = 0.8)",
caption = "Coordinate System: WGS84 (EPSG:4326) | Basemap: Amap"
)在空间点模式分析中,若希望将离散点集转化为闭合多边形 (AOI),常见的边界提取思路包括凸包 (Convex Hull)与凹包 (Concave Hull)。二者的核心差异,在于边界是否允许向内凹陷,以及对点集真实形态的贴合程度。
1. 凸包 (Convex Hull)
定义:
凸包是能够完全包围给定点集的最小凸多边形。其几何特征是:多边形内部任意两点的连线都位于多边形内部,因此边界不会出现明显的内凹结构。
直观理解:
可将其想象为在最外围的点上套上一根橡皮筋,橡皮筋收缩后形成的外轮廓,即为凸包。
适用特点:
凸包适合用于刻画点集的最大外延范围,计算简单、结果稳定。但若点集本身存在明显凹陷或内部空隙,凸包往往会将这些空白区域一并包入,从而造成范围偏大。
2. 凹包 (Concave Hull)
定义:
凹包允许边界根据点集形态向内收缩,因此能够生成非凸的多边形。其结果通常依赖于一定的参数设定 (如收缩程度或边界灵敏度),不同参数会影响边界对局部空隙的保留程度。
直观理解:
可将其理解为在点集外层包裹一层具有收缩性的薄膜,边界会更贴近点云分布,而不是只连接最外侧点位。
适用特点:
凹包更适合用于表达点集的实际空间形态。在商圈、活动区或热点范围识别中,凹包通常比凸包更能反映真实的聚集边界,也更容易剔除大面积无效空白区域。
凹包多边形 vs 凸包多边形
补充说明:
除凹包 (Concave Hull)之外,空间点云边界构建中还有若干更进阶的方法。例如,Alpha Shape / Alpha Hull 常用于根据参数控制边界对点云空隙与凹陷的敏感度;在 R 中,可借助alphahull等相关工具实现。
另一类常见方法是基于快速凹包近似的 Concaveman,在 R 中可通过concaveman包直接调用,适合对sf点对象生成较贴合的外边界。
此外,在部分文献中,也会讨论 \(r\)-convex hull、C-shape 等更强调边界收缩与形态约束的支持估计方法。
本部分不再提供现成代码。请结合本章已经学习的点数据分析方法,自主完成一个小型专题研究。
本章已经涉及点数据读取与裁取、六边形聚合、核密度估计 (KDE)、AOI 提取、邻近性测度以及DBSCAN 聚类等方法。本练习的目标,不再是单一步骤的复现,而是尝试将这些方法围绕一个明确问题进行组合应用。
请从课程数据页面
https://dawn-ecnu.github.io/data/
中选择一个或多个点数据图层 (也可使用本章已出现的数据),围绕某一具体空间问题完成一次自主分析。
建议选题方向 (任选其一,也可自行设计):
方向 A:商业集聚识别
选择某一类 POI (如咖啡店、餐饮、便利店等),识别其在指定区域内的高密度集聚区,并比较
KDE 与 DBSCAN 的结果差异。
方向 B:热点与边界提取
基于点密度结果提取热点范围 (AOI),讨论不同参数设定下边界形态的变化,并解释其空间含义。
方向 C:点数据与城市设施关系
将某类活动点或商业点与公共交通设施 (如地铁站、公交站)结合,分析其是否更倾向于在可达性较高区域集聚。
你的 R Markdown 报告至少应包含以下内容:
研究对象与问题界定
明确说明你选择了什么点数据,研究范围是什么,以及核心问题是什么。
数据处理过程
包括数据读取、坐标系检查、研究范围裁取,以及必要的数据清洗步骤。
至少使用一种密度或聚类方法
可在以下方法中至少选择一种:
至少加入一个补充分析模块
例如:
结果输出与解释
至少输出 2 张图,并用简短文字总结主要发现:
© 华东师范大学 社会发展学院 人口研究所 | DAWN 研究组 | yzliu@soci.ecnu.edu.cn
课程负责人:刘贇喆 本章作者:刘贇喆 | 敖漪宇
最后更新:2026年03月19日 构建环境:R version 4.5.2 (2025-10-31)