小体量经纬度数据聚类:KMeans替代方案及DBSCAN问题排查
针对小规模经纬度数据集的聚类解决方案
一、你的DBSCAN代码问题分析
当前DBSCAN参数设置是导致单簇结果的核心原因:
min_samples=5:对于仅138条数据的小样本集,要求每个核心点周围至少5个邻居的门槛过高,而你的所有点地理位置接近,大部分点都满足该条件,最终被合并成一个大簇。- 调整方向:可尝试将
min_samples降到2-3,同时微调epsilon(比如从5km改为3km),但这种方法很难精准控制簇数量在10-12个区间内。
二、更适配需求的聚类方法推荐
1. 凝聚层次聚类(Agglomerative Clustering)
支持haversine地理距离度量,可通过指定簇数或距离阈值精准匹配你的需求,适合小数据集场景:
from sklearn.cluster import AgglomerativeClustering import pandas as pd import numpy as np from geopy.distance import great_circle coords = pd.read_csv("locs.csv") coords_rad = np.radians(coords.to_numpy()) # 指定生成12个簇,用平均链接法降低离群点影响 cluster = AgglomerativeClustering( n_clusters=12, metric='haversine', linkage='average' ).fit(coords_rad) coords['cluster_label'] = cluster.labels_ # 检查各簇大小 print("各簇样本数量:") print(coords['cluster_label'].value_counts()) # 验证簇内最大距离是否符合5-10km要求 def get_max_cluster_dist(cluster_points): max_dist = 0 for i in range(len(cluster_points)): for j in range(i+1, len(cluster_points)): dist = great_circle(cluster_points.iloc[i], cluster_points.iloc[j]).km if dist > max_dist: max_dist = dist return max_dist print("\n各簇最大地理距离:") for label in coords['cluster_label'].unique(): cluster_points = coords[coords['cluster_label'] == label][['lat', 'long']] print(f"簇{label}: {get_max_cluster_dist(cluster_points):.2f}km")
如果指定簇数后部分簇距离超标,可改用distance_threshold参数(比如设为10),再微调阈值直到簇数量落在10-12区间。
2. K-Medoids(PAM)
K-Means的改进版,以实际数据点作为簇中心,避免K-Means对球面距离的偏差,更适配地理数据:
from sklearn_extra.cluster import KMedoids import pandas as pd import numpy as np coords = pd.read_csv("locs.csv") coords_rad = np.radians(coords.to_numpy()) # 用haversine距离生成12个簇 kmedoids = KMedoids( n_clusters=12, metric='haversine', random_state=42 ).fit(coords_rad) coords['cluster_label'] = kmedoids.labels_ print(coords['cluster_label'].value_counts())
需先安装依赖库:pip install scikit-learn-extra
3. HDBSCAN
DBSCAN的优化版本,能自动识别不同密度的簇,对小数据集更友好,通过min_cluster_size控制簇的最小规模:
import hdbscan import pandas as pd import numpy as np coords = pd.read_csv("locs.csv") coords_rad = np.radians(coords.to_numpy()) # 设置最小簇大小为10,可根据结果调整 clusterer = hdbscan.HDBSCAN( min_cluster_size=10, metric='haversine', cluster_selection_method='eom' ).fit(coords_rad) coords['cluster_label'] = clusterer.labels_ num_clusters = len(set(clusterer.labels_)) - (1 if -1 in clusterer.labels_ else 0) print(f"生成簇数量:{num_clusters}") print(coords['cluster_label'].value_counts())
若出现噪声点(标签为-1),可适当降低min_cluster_size至8,或调整min_samples参数。
三、KMeans的优化用法
若想继续使用KMeans,可先将经纬度转换为球面三维坐标,再进行聚类,能大幅降低欧氏距离的偏差:
from sklearn.cluster import KMeans import pandas as pd import numpy as np coords = pd.read_csv("locs.csv") lat_rad = np.radians(coords['lat']) lon_rad = np.radians(coords['long']) # 转换为三维球面坐标 x = np.cos(lat_rad) * np.cos(lon_rad) y = np.cos(lat_rad) * np.sin(lon_rad) z = np.sin(lat_rad) coords_3d = np.column_stack((x, y, z)) kmeans = KMeans(n_clusters=12, random_state=42).fit(coords_3d) coords['cluster_label'] = kmeans.labels_
内容的提问来源于stack exchange,提问作者Bill Petrosino
相关产品推荐
相关产品推荐

