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

支持距离矩阵输入且可预测新样本簇的Python聚类算法咨询

结论

存在满足需求的聚类算法。你当前使用的AgglomerativeClustering属于转导式聚类,设计目标仅为输出输入距离矩阵对应样本的簇标签,没有训练出可泛化的簇表征,因此要给新样本打标签必须把新样本加入数据集重跑全量聚类、重算包含新样本的全量距离矩阵,天生不支持增量预测。
只要选择归纳式、具备显式簇原型、支持预计算距离输入的聚类算法,就能完全满足“训练后无需重跑全量聚类、无需重算全量距离矩阵,直接预测新样本簇归属”的要求。

最优适配方案:K-Medoids聚类

K-Medoids(围绕中心点聚类)是最适配你场景的算法,核心特性完全匹配需求:

  • 支持precomputed预计算距离矩阵输入,可以直接用你基于随机森林邻近度生成的距离矩阵训练;
  • 训练过程会为每个簇选出一个实际存在的训练样本作为簇中心点(Medoid),仅保存这k个中心点的信息(k为簇数量,通常远小于训练集总样本量);
  • 预测新样本时,仅需要计算新样本到这k个中心点的距离,不需要触碰其他训练样本、不需要重算训练集的n×n全量距离矩阵、不需要重跑聚类流程,直接把新样本分配给距离最近的中心点所属簇即可。

scikit-learn生态中可以通过scikit-learn-extra包的KMedoids实现使用,安装命令为pip install scikit-learn-extra。

适配你随机森林邻近度场景的可运行代码

复用你已有代码的逻辑,仅替换聚类模型、补充预测函数即可:

from sklearn_extra.cluster import KMedoids
import numpy as np
import pandas as pd
# ---- 以下部分完全复用你原有代码的逻辑,加载数据、训练随机森林、生成训练集距离矩阵 ----
from sklearn.ensemble import RandomForestRegressor
from sklearn import datasets

def distanceMatrix(model, X, normalize=True):
    terminals = model.apply(X)
    nTrees = terminals.shape[1]
    a = terminals[:,0]
    proxMat = 1 * np.equal.outer(a, a)
    for i in range(1, nTrees):
        a = terminals[:,i]
        proxMat += 1*np.equal.outer(a, a)
    if normalize:
        proxMat = proxMat / nTrees
    return 1 - proxMat  

iris = datasets.load_iris()
df = pd.DataFrame(iris['data'], columns = iris['feature_names'])
df['target'] = pd.Series(iris['target'], name = 'target_values')
df['target_name'] = df['target'].replace([0,1,2], ['iris-' + species for species in iris['target_names'].tolist()])
df['iris_setosa'] = (df['target_name'] == 'iris-setosa').astype(int)
df['iris_versicolor'] = (df['target_name'] == 'iris-versicolor').astype(int)
df['iris_virginica'] = (df['target_name'] == 'iris-virginica').astype(int)
y = df['petal width (cm)']
X = df.drop(['target','target_name','petal width (cm)'], axis = 1)
overfitted_model = RandomForestRegressor(n_estimators=250, min_samples_leaf=10, random_state=42)
overfitted_model.fit(X, y)
distance_matrix = distanceMatrix(overfitted_model, X, normalize=True)

# ---- 替换原有层次聚类为K-Medoids ----
cluster_model = KMedoids(n_clusters=3, metric='precomputed', random_state=42)
cluster_model.fit(distance_matrix)
df['label'] = cluster_model.labels_
# 提取每个簇的medoid对应的训练样本,预测阶段仅需要这几个样本
medoid_indices = cluster_model.medoid_indices_
medoid_samples = X.iloc[medoid_indices]
medoid_terminals = overfitted_model.apply(medoid_samples)

# ---- 新样本预测函数,无全量重计算 ----
def predict_new(new_X):
    new_terminals = overfitted_model.apply(new_X)
    n_new = len(new_terminals)
    dist_to_medoids = np.zeros((n_new, len(medoid_indices)))
    for i in range(n_new):
        # 仅计算新样本到k个medoid的距离,计算量和训练集总样本量无关
        same_leaf_ratio = np.mean(new_terminals[i] == medoid_terminals, axis=1)
        dist_to_medoids[i] = 1 - same_leaf_ratio
    return cluster_model.cluster_centers_[np.argmin(dist_to_medoids, axis=1)]

# 测试预测(示例取前5个样本当新样本)
test_new_samples = X.iloc[:5]
print("新样本预测簇标签:", predict_new(test_new_samples))
其他可选方案
  • HDBSCAN:支持预计算距离矩阵输入,训练后提供近似预测方法,不需要重跑全量聚类,但预测阶段需要计算新样本到所有训练集核心点的距离,训练集体量较大时预测成本高于K-Medoids,适合非凸簇分布的场景。
  • 原型映射法:如果已经用转导式聚类(比如你之前用的层次聚类)拿到了训练集标签,可以训练一个NearestCentroid分类器拟合训练集的簇标签,预测阶段仅需要计算新样本到每个簇质心的距离,但这种方法是二次拟合的近似方案,精度略低于原生支持预测的聚类模型。

注:对随机森林邻近度计算感兴趣的读者,可参考决策森林邻近度相关的公开教程内容拓展学习。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:06:28