如何通过线性划分实现三类线性分布数据的聚类?
如何通过线性划分实现三类线性分布数据的聚类?
看起来你已经试过不少标准聚类算法,但因为你的数据是三条明显的线性分布,这些基于距离或密度的算法完全没get到你想要的划分方式——毕竟它们的设计初衷不是处理这种线性分离的集群嘛!别担心,咱们可以直接针对数据的线性特点来解决,给你几个实用的方法:
方法一:手动拟合分割线(简单直接,适合规律明显的场景)
既然你已经从图上看到了清晰的三条线,那最直接的方式就是手动找出两条能把它们分开的直线,然后根据点相对于直线的位置来归类。
- 第一步:观察你的可视化图表,确定分割线的方程。假设你是用
line_position作为x轴,real_seq作为y轴绘图,那两条分割线可以表示为y = m1*x + c1和y = m2*x + c2,你需要根据图中的位置估算出m(斜率)和c(截距)的数值。 - 第二步:用代码给每个点判断归属,比如用Python+Pandas的话:
import pandas as pd # 读取你的数据 df = pd.read_csv("your_data_file.csv") # 根据你的图表调整这两个线的参数 m1, c1 = 400, 12000 # 第一条分割线的斜率和截距 m2, c2 = 400, 32000 # 第二条分割线的斜率和截距 # 定义集群分配逻辑 def assign_cluster(row): x = row['line_position'] y = row['real_seq'] if y < m1 * x + c1: return 0 # 第一个集群 elif y > m2 * x + c2: return 2 # 第三个集群 else: return 1 # 中间的集群 # 给每个数据行添加集群标签 df['cluster'] = df.apply(assign_cluster, axis=1)
- 优点:完全贴合你看到的图形规律,零训练成本;缺点:需要人工调整参数,如果数据后续有变化,可能要重新校准分割线。
方法二:用线性分类器自动找分割线(更灵活,适合自动化需求)
你可以把这个问题转化为一个半监督的分类任务:先手动给一小部分数据打标签,再训练线性分类器来自动划分所有数据。
- 第一步:从三个集群里各挑几个典型样本(比如每个集群选3-5个点),手动标记它们的集群编号。
- 第二步:用这些带标签的样本训练线性分类器(比如逻辑回归、线性核的SVM),然后用模型预测所有数据的集群归属:
from sklearn.linear_model import LogisticRegression import pandas as pd df = pd.read_csv("your_data_file.csv") # 手动标记部分样本(这里的索引要对应你数据里的典型点) labeled_idx = [0, 4, 10, 15] # 例子索引,你要自己调整 df.loc[labeled_idx, 'label'] = [0, 1, 2, 0] # 给这些点分配集群标签 # 分离带标签的特征和标签 X_labeled = df.dropna(subset=['label'])[['line_position', 'real_seq']] y_labeled = df.dropna(subset=['label'])['label'] # 训练多分类逻辑回归模型 clf = LogisticRegression(multi_class='multinomial', solver='lbfgs') clf.fit(X_labeled, y_labeled) # 预测所有数据的集群 df['cluster'] = clf.predict(df[['line_position', 'real_seq']])
- 优点:不需要手动算分割线参数,模型会自动学习数据的线性分离规律;缺点:需要少量手动标记的样本,但标记工作量很小。
方法三:拟合每条线,按距离分集群(最贴合“三条线”的本质)
既然数据本身是三条线,那我们可以先给每条线拟合出线性模型,然后把每个点分到距离最近的那条线对应的集群里。
- 第一步:先通过简单的阈值(比如根据y轴范围)把数据粗略分成三个子集,然后对每个子集拟合线性回归模型。
- 第二步:计算每个点到三条拟合线的垂直距离,距离最近的线对应的集群就是这个点的归属:
from sklearn.linear_model import LinearRegression import pandas as pd import numpy as np df = pd.read_csv("your_data_file.csv") # 先粗略划分三个子集(根据你观察的y轴范围调整阈值) sub1 = df[df['real_seq'] < 15000] sub2 = df[(df['real_seq'] >= 15000) & (df['real_seq'] < 30000)] sub3 = df[df['real_seq'] >= 30000] # 给每个子集拟合线性回归模型 line_models = [] for subset in [sub1, sub2, sub3]: X = subset[['line_position']] y = subset['real_seq'] lr = LinearRegression() lr.fit(X, y) line_models.append(lr) # 计算点到直线的垂直距离 def calc_distance(x, y, model): m = model.coef_[0] b = model.intercept_ # 直线方程:mx - y + b = 0,垂直距离公式 return abs(m * x - y + b) / np.sqrt(m**2 + 1) # 分配集群 def assign_cluster(row): x = row['line_position'] y = row['real_seq'] distances = [calc_distance(x, y, model) for model in line_models] return distances.index(min(distances)) df['cluster'] = df.apply(assign_cluster, axis=1)
- 优点:完全基于“点到线的距离”来划分,结果最贴合数据的线性分布本质;缺点:需要初始的粗略划分,但这个划分不需要太精确,只要能把三个集群大致分开就行。
总结
你的数据属于线性分离型集群,KMeans这类基于中心的聚类算法自然会失效,而上面这三种方法都是针对线性划分的场景设计的,你可以根据自己的需求选择:
- 如果数据规律稳定,选手动拟合分割线最快;
- 如果想自动化,用线性分类器更省心;
- 如果追求最贴合“三条线”的划分逻辑,就选拟合线条再算距离的方法。
备注:内容来源于stack exchange,提问作者Pavel Botsman
相关产品推荐
相关产品推荐

