机器学习+城市规划第十期:城市规划中的多尺度地理加权回归
🧭 引言
在空间数据分析中,“一个因素对目标变量的影响是否处处相同?”——这是传统回归模型难以解答的问题。GWR(地理加权回归)让我们迈出第一步,MGWR(多尺度 GWR)则进一步揭示了:
不同解释变量对因变量的影响,可能在空间上有不同的作用尺度。
本次课程从原理到实战,深入理解 MGWR,并基于 Python 在城市规划数据中实现一个完整的 MGWR 分析流程。
1️⃣ 什么是 MGWR?
🔹 背景:GWR 的限制
GWR(Geographically Weighted Regression)允许每个地理位置上的回归系数不同,适合建模空间异质性。其基本形式:
y i = β 0 ( u i , v i ) + ∑ k β k ( u i , v i ) x i k + ε i y_i = \beta_0(u_i,v_i) + \sum_k \beta_k(u_i,v_i) x_{ik} + \varepsilon_i yi=β0(ui,vi)+k∑βk(ui,vi)xik+εi
其中, ( u i , v i ) (u_i, v_i) (ui,vi) 是地理坐标, β k \beta_k βk 是局部回归系数。
🔍 但 GWR 的一个核心假设是:所有变量共享相同的带宽(作用范围),这显然不现实。
🔹 MGWR:考虑不同变量的空间尺度
MGWR(Multiscale GWR)引入了 变量级别的带宽选择机制,允许:
- 人口密度可能在 1km 内显著影响出行
- 交通密度可能在 5km 内才产生作用
其建模思想是为每个解释变量都寻找最优的空间尺度 b k b_k bk,写作:
y i = β 0 ( u i , v i ) + ∑ k β k b k ( u i , v i ) x i k + ε i y_i = \beta_0(u_i,v_i) + \sum_k \beta_k^{b_k}(u_i,v_i) x_{ik} + \varepsilon_i yi=β0(ui,vi)+k∑βkbk(ui,vi)xik+εi
✅ 相比 GWR 的优势:
特征 | GWR | MGWR |
---|---|---|
带宽 | 单一 | 多尺度(每变量一带宽) |
空间异质性建模 | 支持 | 支持,更细致 |
精度 | 中 | 高 |
计算开销 | 中 | 高(但更真实) |
2️⃣ MGWR 在城市规划中的优势
城市规划中常见问题包括:
- 🛴 微出行需求分析(如共享单车)
- 🌳 绿地对热岛效应的影响
- 🚦 道路密度对拥堵的空间作用差异
这些问题都具备空间不均匀性和多尺度驱动因子的特点。MGWR 能清晰回答:
- 哪些区域受某变量影响更大?
- 哪些变量的影响范围是“远程” vs “局部”?
3️⃣ Python 实现 MGWR 模型(含自动带宽搜索)
以下是你项目中的完整 MGWR 脚本,逐步讲解如下:
📦 第一步:导入依赖
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
import numpy as np
np.float = float # 兼容 numpy 老接口
from mgwr.gwr import MGWR # ✅ 正确导入新版 MGWR 类
from mgwr.sel_bw import Sel_BW
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
from gwr_tools import save_gwr_summary # 自定义函数:保存模型结果
我们使用了 mgwr
包,确保用的是官方版本(conda install -c conda-forge mgwr
)。
🧹 第二步:数据清洗与准备
print("🔍 正在读取和清洗数据...")
df = pd.read_csv("D:/桌面/祝贺老师Python学习/地理加权回归/多尺度模型/2000yangben.csv")
df.columns = ["Latitude", "Longitude", "Delay time", "Temperature", "Humidity", "Visibility", "Wind speed"]
# 强制转为数值型,清理非法值
df = df.apply(pd.to_numeric, errors="coerce")
df.replace([np.inf, -np.inf], np.nan, inplace=True)
df.dropna(inplace=True)
df.reset_index(drop=True, inplace=True)
# 检查清洗结果
print("✅ 数据完整性检查:")
print("是否存在 NaN:", df.isna().any().any())
print("是否存在 inf:", np.isinf(df.values).any())
确保数据清洗无误,尤其是经纬度、因变量、解释变量列没有 NaN 或 Inf。
🌍 第三步:空间坐标转换(WGS84 → 米制)
geometry = [Point(xy) for xy in zip(df["Longitude"], df["Latitude"])]
gdf = gpd.GeoDataFrame(df.copy(), geometry=geometry)
gdf.set_crs(epsg=4326, inplace=True)
gdf = gdf.to_crs(epsg=3857)
MGWR 要计算空间权重,必须使用投影坐标系(如 EPSG:3857),而不是经纬度。
📐 第四步:准备建模数据
coords = np.array([(point.x, point.y) for point in gdf.geometry])
y = df["Delay time"].values.reshape(-1, 1)
var_names = ["Temperature", "Humidity", "Visibility", "Wind speed"]
X = df[var_names].values
📐 第五步:数据检查
assert not np.isnan(X).any(), "❌ X 中存在 NaN"
assert not np.isinf(X).any(), "❌ X 中存在 inf"
assert not np.isnan(y).any(), "❌ y 中存在 NaN"
assert not np.isinf(y).any(), "❌ y 中存在 inf"
🧠 第六步:多尺度带宽搜索 + 模型拟合
print("📊 正在为每个变量自动选择最优带宽,请稍候(多尺度)...")
selector = Sel_BW(coords, y, X, multi=True)
bws = selector.search()
print(f"✅ 每个变量的最优带宽为:{bws}")
print("🚀 正在拟合 MGWR 模型...")
model = MGWR(coords=coords, y=y, X=X, selector=selector, constant=True)
results = model.fit()
print("\n======= MGWR 模型结果汇总 =======")
print(results.summary())
这里:
multi=True
开启多尺度搜索selector
会为每个变量选择最优带宽constant=True
表示添加截距项(建议开启)
📤 第七步:保存输出(不包括 local R²)
for i, name in enumerate(var_names):
gdf[f"MGWR_coef_{name}"] = results.params[:, i]
gdf["MGWR_resid"] = results.resid_response
gdf.to_file("mgwr_result.geojson", driver="GeoJSON")
print("📍 已保存为 'mgwr_result.geojson'")
⚠️ 注意:
MGWR 多尺度模式 不支持
results.localR2
,调用会报错。
🧾 第八步:保存模型摘要 CSV
save_gwr_summary(results, model, filename_prefix="mgwr_with_search")
print("✅ 模型摘要 CSV 已保存(含参数与诊断信息)")
你自定义的封装函数将摘要写入 CSV,包含:
- 每个变量的平均系数、标准差、极值
- 模型 AIC、RSS 等诊断指标
✅ 总结与应用建议
MGWR 是对 GWR 的有力升级,尤其适合:
场景 | 变量行为 |
---|---|
城市热环境、绿地影响 | 多尺度 |
居住密度 vs 交通出行 | 空间异质性强 |
区域房价建模 | 局部市场规律 |
@原创声明:本教程由课题组内部教学使用,利用CSDN平台记录,不进行任何商业盈利。