首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python LISA 局部空间自相关实战:找出谁跟谁扎堆

Python LISA 局部空间自相关实战:找出谁跟谁扎堆

作者头像
renhai
发布2026-06-23 17:42:13
发布2026-06-23 17:42:13
180
举报

本系列第二篇。上篇讲了全局 Moran’s I(“有没有聚集”),本篇讲 LISA(“谁跟谁聚集”)。建议先读 Part 1[1]。

1. 从全局到局部

上篇的结论:波动率的全局 Moran’s I = 0.30(p = 0.001),说明"波动大的城市倾向于挨在一起"。但 Moran’s I 是一个全局指标——它只告诉你整体上有聚集,不告诉你哪些城市在聚集

这就好比说"班上有小团体",但没说谁跟谁是一伙的。LISA(Local Indicators of Spatial Association)就是用来回答这个问题的。

2. LISA 是什么?

LISA 把 Moran’s I 拆到每个城市。每个城市得到一个局部 Moran’s I 值和对应的 p 值,然后按四象限分类:

类型

含义

例子

HH(高-高)

该城市值高,邻居也高

三亚波动率高,周围海口、北海也高

LL(低-低)

该城市值低,邻居也低

秦皇岛波动率低,周围也低

HL(高-低)

该城市值高,但邻居低

重庆波动率高,但周围四川城市低

LH(低-高)

该城市值低,但邻居高

南宁波动率低,但旁边北海高

不显著

p > 0.05,不能排除随机

大部分城市

HH 和 LL 是聚类(同类扎堆),HL 和 LH 是异常值(跟邻居反着来)。

3. Step 1:计算 LISA

代码语言:javascript
复制
from esda.moran import Moran_Local

# 假设 w 是上篇构建的 KNN 权重矩阵,gdf 是 GeoDataFrame
lisa = Moran_Local(gdf['volatility'].values, w)

# 提取结果
gdf['lisa_I'] = lisa.Is          # 每个城市的局部 Moran's I
gdf['lisa_p'] = lisa.p_sim       # p 值(排列检验)
gdf['lisa_q'] = lisa.q           # 象限(1=HH, 2=LH, 3=LL, 4=HL)

# 分类
gdf['cluster'] = '不显著'
gdf.loc[(gdf['lisa_p'] < 0.05) & (gdf['lisa_q'] == 1), 'cluster'] = 'HH'
gdf.loc[(gdf['lisa_p'] < 0.05) & (gdf['lisa_q'] == 2), 'cluster'] = 'LH'
gdf.loc[(gdf['lisa_p'] < 0.05) & (gdf['lisa_q'] == 3), 'cluster'] = 'LL'
gdf.loc[(gdf['lisa_p'] < 0.05) & (gdf['lisa_q'] == 4), 'cluster'] = 'HL'

# 统计
print(gdf['cluster'].value_counts())
代码语言:javascript
复制
不显著    62
HH        4
HL        2
LH        1
LL        1

70 城里只有 8 个通过了 p < 0.05 的显著性检验,其余 62 个在统计上跟邻居没有显著的联动关系。

4. Step 2:列出显著城市

代码语言:javascript
复制
sig = gdf[gdf['lisa_p'] < 0.05][['CITY', 'volatility', 'cum_return', 'cluster', 'lisa_p']]
print(sig.sort_values('cluster').to_string(index=False))
代码语言:javascript
复制
 CITY  volatility  cum_return cluster  lisa_p
  秦皇岛    0.70%      51.4%      LL   0.027
  南宁      0.79%      61.2%      LH   0.020
  丹东      0.87%      43.7%      HL   0.045
  重庆      0.82%     104.9%      HL   0.045
  三亚      2.04%     186.8%      HH   0.002
  北海      1.30%      84.8%      HH   0.004
  海口      1.82%     184.6%      HH   0.002
  湛江      0.87%      69.1%      HH   0.002

HH 簇:三亚、海口、北海、湛江——全部在海南+北部湾沿海地带。这四个城市的波动率远超全国均值,且彼此空间相连。

HL 异常:丹东、重庆——波动率高,但周围城市波动率低。丹东靠近朝鲜边境,房地产市场特殊;重庆是直辖市,经济结构跟周边四川城市差异大。

LH 异常:南宁——波动率低,但旁边的北海波动率高。南宁是省会,房价相对稳定;北海是旅游城市,投机氛围浓。

LL 簇:秦皇岛——波动率低,周围的京津冀城市也低。京津冀是政策高度管控区域,市场波动被压制。

5. Step 3:画 LISA 聚类地图

LISA 的最终呈现是一张地图,比表格直观 10 倍:

代码语言:javascript
复制
import geopandas as gpd
import matplotlib.pyplot as plt

# 加载行政区划底图(需要一个中国地级市 shapefile)
admin_gdf = gpd.read_file('2023年地级.shp')

fig, ax = plt.subplots(1, 1, figsize=(16, 12))

# 画底图
admin_gdf.plot(ax=ax, color='#fafafa', edgecolor='#dddddd', linewidth=0.3)

# 颜色方案
LISA_COLORS = {'不显著': '#cccccc', 'HH': '#e15759', 'LH': '#76b7b2', 'LL': '#4e79a7', 'HL': '#f28e2b'}

for cluster, color in LISA_COLORS.items():
    mask = gdf['cluster'] == cluster
    if mask.any():
        subset = gdf[mask]
        subset.plot(ax=ax, color=color, markersize=100, alpha=0.85,
                    label=cluster, edgecolor='black' if cluster != '不显著' else None,
                    linewidth=0.5 if cluster != '不显著' else 0)

# 标注显著城市
for _, row in gdf[gdf['lisa_p'] < 0.05].iterrows():
    ax.annotate(row['CITY'], (row.geometry.x, row.geometry.y),
                fontsize=10, fontweight='bold', xytext=(10, 10),
                textcoords='offset points',
                bbox=dict(boxstyle='round,pad=0.2', facecolor='white', alpha=0.8, edgecolor='gray'))

ax.set_xlim(73, 136)
ax.set_ylim(17, 54)
ax.set_title('波动率 LISA 聚类图', fontsize=16, fontweight='bold')
ax.legend(loc='lower left', fontsize=10, framealpha=0.9)
ax.grid(True, alpha=0.2)
plt.savefig('lisa_volatility.png', dpi=150, bbox_inches='tight')

波动率 LISA 聚类图

地图上绝大多数是灰色(不显著),只有 8 个点有颜色。HH 红色点集中在右下角的海南+北部湾一带,形成一个明显的空间簇。

6. Step 4:画波动率气泡地图

除了 LISA 聚类,还可以用气泡大小+颜色直接展示波动率的空间分布:

代码语言:javascript
复制
fig, ax = plt.subplots(1, 1, figsize=(16, 12))
admin_gdf.plot(ax=ax, color='#fafafa', edgecolor='#dddddd', linewidth=0.3)

# 气泡大小 = 波动率,颜色 = 波动率
gdf.plot(ax=ax, column='volatility', cmap='YlOrRd',
         markersize=gdf['volatility'] * 40, alpha=0.8,
         legend=True, edgecolor='black', linewidth=0.3,
         legend_kwds={'label': '波动率', 'orientation': 'horizontal', 'shrink': 0.6})

# 标注 Top 5
for _, row in gdf.nlargest(5, 'volatility').iterrows():
    ax.annotate(f\"{row['CITY']}\\n{row['volatility']*100:.0f}%\",
                (row.geometry.x, row.geometry.y), fontsize=9, fontweight='bold',
                xytext=(10, 10), textcoords='offset points',
                bbox=dict(boxstyle='round,pad=0.2', facecolor='white', alpha=0.8))

ax.set_xlim(73, 136)
ax.set_ylim(17, 54)
ax.set_title('70城房价波动率空间分布', fontsize=16, fontweight='bold')
plt.savefig('volatility_map.png', dpi=150, bbox_inches='tight')

70城波动率空间分布

气泡图比 LISA 聚类图信息更丰富——不只看到谁跟谁扎堆,还能看到每个城市的具体波动率。三亚的气泡(204%)几乎是平顶山(49%)的 4 倍大。

7. Step 5:稳健性——k 值对 LISA 的影响

上篇验证了全局 Moran’s I 对 k 值稳健。LISA 也需要验证:

代码语言:javascript
复制
for k in [3, 5, 7]:
    w_k = lps.weights.KNN.from_dataframe(gdf, k=k)
    w_k.transform = 'r'
    lisa_k = Moran_Local(gdf['volatility'].values, w_k)
    sig_mask = lisa_k.p_sim < 0.05
    hh_mask = sig_mask & (lisa_k.q == 1)
    hh_cities = gdf[hh_mask]['CITY'].tolist()
    print(f'k={k}: {sig_mask.sum()} 个显著, HH={hh_cities}')
代码语言:javascript
复制
k=3: 6 个显著, HH=['三亚', '海口', '湛江']
k=5: 8 个显著, HH=['三亚', '北海', '海口', '湛江']
k=7: 11 个显著, HH=['三亚', '北海', '广州', '海口', '深圳', '湛江']

核心 HH 簇(三亚、海口、湛江)在所有 k 值下都稳定存在。北海在 k=5/7 时加入,k=3 时退出——说明它跟三亚/海口的空间连接是中等距离的,不是最近的 3 个邻居之一。广州和深圳在 k=7 时才进入聚类,属于更大范围的南方沿海波动带的边缘。

8. 本篇小结

类型

城市

含义

HH(高-高)

三亚、海口、北海、湛江

海南+北部湾波动率热点

HL(高-低)

丹东、重庆

波动大但跟邻居不同步

LH(低-高)

南宁

稳定但被高波动邻居包围

LL(低-低)

秦皇岛

京津冀低波动区

一句话:全国只有海南+北部湾这一片形成了显著的波动率聚集。买房选城市时,如果你的目标城市在这个区域,要意识到整个片区的风险是联动的。

9. 下篇预告

区域对比 + 时间序列 + 总结——7 个区域的涨幅和波动率排名、10 城 20 年走势、以及最终结论。

参考链接

[1] /blog/geospatial-data-analysis/python-spatial-autocorrelation-housing-70cities

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 renhailab 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 从全局到局部
  • 2. LISA 是什么?
  • 3. Step 1:计算 LISA
  • 4. Step 2:列出显著城市
  • 5. Step 3:画 LISA 聚类地图
  • 6. Step 4:画波动率气泡地图
  • 7. Step 5:稳健性——k 值对 LISA 的影响
  • 8. 本篇小结
  • 9. 下篇预告
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档