GEE环境下无监督聚类精度评估及轮廓分数报错解决
无监督NDVI聚类评估与报错解决
报错原因分析
silhouette_score要求输入的特征数据必须是2D数组(形状为(n_samples, n_features)),你传入的clustering.select("ndvi")大概率是1D数组(比如单波段NDVI的扁平化像素值)或未转换为numpy数组的影像对象,导致scikit-learn无法识别,抛出维度不匹配的错误。
解决报错并计算轮廓系数
根据你使用的影像处理环境,给出具体修正方案:
场景1:Google Earth Engine(GEE)环境
如果clustering是GEE的Image对象,需要先提取像素值并转换为符合要求的numpy数组:
import numpy as np from sklearn.metrics import silhouette_score # 替换成你的研究区域和影像分辨率 your_roi = ee.Geometry.Rectangle([xmin, ymin, xmax, ymax]) your_scale = 30 # 提取NDVI像素值并转为2D数组 ndvi_values = clustering.select("ndvi").sampleRegion( geometry=your_roi, scale=your_scale, geometries=False ).aggregate_array("ndvi").getInfo() ndvi_array = np.array(ndvi_values).reshape(-1, 1) # 关键:转为(n_samples, 1)的2D格式 # 提取聚类ID数组 cluster_ids = clustering.select("clusters").sampleRegion( geometry=your_roi, scale=your_scale, geometries=False ).aggregate_array("clusters").getInfo() cluster_array = np.array(cluster_ids) # 计算平均轮廓系数 silhouette_avg = silhouette_score(ndvi_array, cluster_array) print(f"平均轮廓系数: {silhouette_avg}")
场景2:本地影像(如rasterio读取)
如果是本地存储的TIFF影像,需要读取后扁平化并调整维度:
import numpy as np import rasterio from sklearn.metrics import silhouette_score # 读取NDVI聚类影像 with rasterio.open("ndvi_clustered.tif") as src: ndvi = src.read(1).flatten() # 读取单波段并扁平化 ndvi_array = ndvi.reshape(-1, 1) # 转为2D数组 nodata = src.nodata # 读取聚类ID影像 with rasterio.open("clusters.tif") as src: clusters = src.read(1).flatten() # 过滤无数据值(可选但推荐) mask = (ndvi_array != nodata) & (clusters != nodata) ndvi_filtered = ndvi_array[mask] clusters_filtered = clusters[mask] # 计算轮廓系数 silhouette_avg = silhouette_score(ndvi_filtered, clusters_filtered) print(f"平均轮廓系数: {silhouette_avg}")
无监督聚类的其他评估指标
无真实标签时,除了轮廓系数,还可以用以下指标评估聚类效果:
- Calinski-Harabasz指数:类间离散度与类内离散度的比值,值越大聚类效果越好
- Davies-Bouldin指数:衡量类内相似度与类间距离的平衡,值越小聚类效果越好
示例代码:
from sklearn.metrics import calinski_harabasz_score, davies_bouldin_score # 计算Calinski-Harabasz指数 ch_score = calinski_harabasz_score(ndvi_filtered, clusters_filtered) print(f"Calinski-Harabasz指数: {ch_score}") # 计算Davies-Bouldin指数 db_score = davies_bouldin_score(ndvi_filtered, clusters_filtered) print(f"Davies-Bouldin指数: {db_score}")
注意事项
- 轮廓系数取值范围为[-1,1]:接近1表示样本聚类合理,接近-1表示样本应该归为其他类,0表示样本处于聚类边界
- 必须过滤无数据值(如NaN、影像nodata值),否则会干扰计算结果
- 如果存在仅含单个样本的聚类,
silhouette_score会报错,需提前过滤这类聚类
内容的提问来源于stack exchange,提问作者th145
相关产品推荐
相关产品推荐

