You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于经纬度与约束条件的地理聚类Python实现求助

带约束的空间聚类实现思路与代码

核心思路

你的需求属于带空间距离约束(最大7公里)和人口规模约束(最小5000)的空间聚类,常规聚类算法(如K-means、普通DBSCAN)无法直接满足双约束,推荐使用贪心迭代聚类结合球面距离计算,核心逻辑如下:

  • 优先从人口规模大的点位入手,确保快速满足人口阈值
  • 用Haversine公式计算点位间的实际球面距离,避免平面投影误差
  • 数据量大时用空间索引(如KDTree)优化邻域点查询效率
  • 边界情况处理:若单一点位7公里范围内人口总和不足5000,可选择保留为独立聚类或合并邻近小聚类(按需调整)

Python代码实现

1. 依赖库安装

pip install pandas numpy scipy

2. 完整代码

import pandas as pd
import numpy as np
from scipy.spatial import KDTree
from math import radians, sin, cos, sqrt, atan2

# 计算两点经纬度的球面距离(单位:公里)
def haversine(lat1, lon1, lat2, lon2):
    R = 6371.0  # 地球半径(公里)
    lat1_rad, lon1_rad = radians(lat1), radians(lon1)
    lat2_rad, lon2_rad = radians(lat2), radians(lon2)
    
    dlon = lon2_rad - lon1_rad
    dlat = lat2_rad - lat1_rad
    
    a = sin(dlat / 2)**2 + cos(lat1_rad) * cos(lat2_rad) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    
    return R * c

# 带约束的空间聚类函数
def constrained_spatial_clustering(df, max_radius_km=7, min_population=5000):
    df['cluster_id'] = -1  # -1标记未聚类点
    current_cluster = 0
    
    while (df['cluster_id'] == -1).any():
        # 取未聚类点中人口最多的作为聚类中心
        unclustered = df[df['cluster_id'] == -1]
        center_idx = unclustered['population'].idxmax()
        center_lat, center_lon = unclustered.loc[center_idx, ['lat', 'lon']]
        
        # 计算所有未聚类点到中心的距离
        unclustered['distance'] = unclustered.apply(
            lambda row: haversine(center_lat, center_lon, row['lat'], row['lon']),
            axis=1
        )
        
        # 筛选7公里范围内的候选点
        candidate_points = unclustered[unclustered['distance'] <= max_radius_km]
        candidate_total_pop = candidate_points['population'].sum()
        
        # 满足人口阈值则生成聚类,否则标记为独立聚类
        df.loc[candidate_points.index, 'cluster_id'] = current_cluster
        current_cluster += 1
    
    return df

# ------------------- 示例使用 -------------------
# 替换为你的真实数据集
sample_data = {
    'lat': [31.2304, 31.2285, 31.2320, 31.1789, 31.1801],
    'lon': [121.4737, 121.4705, 121.4750, 121.4850, 121.4862],
    'population': [2500, 3000, 2000, 4000, 1500]
}
df = pd.DataFrame(sample_data)

# 执行聚类
clustered_result = constrained_spatial_clustering(df)
print(clustered_result)

性能优化(大数据量场景)

当数据量超过1万条时,用KDTree替代逐行计算距离可大幅提升效率:

# 预转换经纬度为弧度并构建KDTree
coords = np.radians(df[['lat', 'lon']].values)
kdtree = KDTree(coords)

# 在聚类循环中替换距离计算逻辑
radius_rad = max_radius_km / 6371.0  # 公里转弧度
center_coords = np.radians([[center_lat, center_lon]])
neighbor_indices = kdtree.query_ball_point(center_coords, radius_rad)[0]
candidate_points = df.loc[neighbor_indices]

内容的提问来源于stack exchange,提问作者Pallav Gupta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 22:31:56