带约束的K-means 聚类算法

1. 前言

上一期学习了K-means聚类算法,聚类是不受到限制的,单纯的无监督学习,但是当存在一些约束时,比如对每一簇的聚类样本点数量有限制,或者每个样本点带需求,每一簇存在满足约束的最大能力,这时候应该怎么添加约束,并且不破坏聚类的效果。

2. 场景构建

假设场景:有一定数量的区域需要分配邮递员配送信件,怎么将区域划分给邮递员?每个区域有一定的需求量,一个邮递员一天的工作量只能满足一定的需求,那么应该怎么将区域划分给邮递员?考虑到成本问题,这里设置一个目标——在满足需求的情况下最小化邮递员数量。

这样的场景在快递行业应该很常见,不太清楚实际业务中是怎么分配的,但我觉得带约束的聚类算法应该能求解一个可行解,为了给K-means加约束构想的场景,场景简化了很多,可能不太符合实际,欢迎提建议。

3. 带约束的K-means 聚类设计

K-means聚类算法流程

算法说明:由于存在需求约束,那么就存在最小的K(总需求/簇的能力),可以从最小值K开始遍历。而约束就加在(3)将对象分配到最相似的簇中,具体修改为:在满足约束的情况下,将对象分配到最相似的簇中,如果最相似的簇无法容纳,就找第二相似的簇,依次类推。

遍历改进:对遍历对象进行一个小的修改,通常K-means是随机/按列表顺序遍历对象,将对象分配到最相似的簇,这里改进为:取所有对象中距离某个簇最近的点,优先分配(这算是随机/按列表顺序遍历对象的一个特殊情况)。

初始解敏感:为了减小K-means对初始解敏感的问题,这里采用多次求解的方式保留最优的方式降低对初始解的依赖。

效果评价:聚类效果使用轮廓系数进行评价。

3. python实现

# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import random
import math
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']  # 添加这条可以让图形显示中文def calDistance(centers,nodes):''' 计算节点间距离输入:centers-中心,nodes-节点;输出:距离矩阵-dis_matrix'''dis_matrix = pd.DataFrame(data=None,columns=range(len(centers)),index=range(len(nodes)))for i in range(len(nodes)):xi,yi = nodes[i][0],nodes[i][1]for j in range(len(centers)):xj,yj = centers[j][0],centers[j][1]dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)return dis_matrixdef scatter_diagram(clusters,nodes):'''#画路径图输入:nodes-节点坐标;输出:散点图'''for cluster in clusters:x,y= [],[]for Coordinate in cluster:x.append(Coordinate[0])y.append(Coordinate[1])plt.scatter(x, y,alpha=0.8,)plt.xlabel('x')plt.ylabel('y')plt.show()def distribute(center,nodes,K,demand,d_limit):'''将节节点分给最近的中心输入:center-中心,nodes-节点,K-类数量,demand-需求,d_limit-一个簇的满足需求的能力输出:新的簇-clusters,簇的需求-clusters_d'''clusters = [[] for i in range(K)]#簇label = [None for i in range(len(nodes))]clusters_d = [0 for i in range(K)]#簇需求dis_matrix = calDistance(center,nodes).astype('float64')for i in range(len(dis_matrix)):row, col = dis_matrix.stack().idxmin()node = nodes[row]j = 1while clusters_d[col] + demand[row] > d_limit:#检验约束if j < K: j += 1dis_matrix.loc[row,col] = math.pow(10,10)col = dis_matrix.loc[row,:].idxmin()else:#所有类都不满足需求量约束print("K较小")scatter_diagram(clusters,nodes)return None#满足约束正常分配clusters[col].append(node)label[row] = colclusters_d[col] += demand[row]dis_matrix.loc[row,:] = math.pow(10,10)return clusters,clusters_d,labeldef cal_center(clusters):'''计算簇的中心输入:clusters-类坐标;输出:簇中心-new_center'''new_center = []for cluster in clusters:x,y= [],[]for Coordinate in cluster:x.append(Coordinate[0])y.append(Coordinate[1])x_mean = np.mean(x)y_mean = np.mean(y)new_center.append((round(x_mean,2),round(y_mean,2)))return new_centerif __name__ == "__main__":#输入数据nodes = [(11, 36),(13, 35),(14, 12),(25, 22),(15, 11),(16, 24),(14, 30),(16, 32),(26, 10),(27, 31),(22, 29),(1, 29),(20, 29),(17, 15),(5, 38),(3, 15),(22, 20),(4, 13),(4, 22),(12, 18),(23, 12),(18, 15),(5, 13),(9, 27),(17, 36),(2, 14),(1, 16),(7, 15),(25, 15),(19, 26),(25, 40),(26, 34),(25, 35),(2, 36),(29, 24),(17, 17),(8, 26),(4, 14),(5, 25),(6, 37),(1, 14),(6, 39),(11, 13),(10, 20),(21, 11),(5, 19),(5, 35),(1, 34),(16, 39),(19, 24),(39, 31),(49, 31),(41, 50),(31, 33),(32, 40),(35, 30),(31, 39),(34, 48),(42, 32),(32, 35),(35, 33),(35, 34),(43, 41),(35, 47),(49, 36),(37, 41),(43, 46),(41, 41),(45, 50),(41, 35),(45, 44),(41, 30),(43, 33),(31, 45),(48, 32),(39, 49),(38, 42),(33, 39),(49, 33),(43, 44),(32, 30),(40, 47),(36, 46),(47, 47),(37, 33),(35, 31),(42, 38),(43, 47),(30, 47),(30, 30),(37, 34),(41, 45),(27, 33),(42, 39),(43, 43),(50, 43),(28, 40),(35, 41),(32, 41),(31, 30)]demand = [3,3,5,9,6,1,4,8,8,3,6,5,6,4,1,4,7,1,3,6,2,5,7,2,2,1,9,3,7,8,4,3,1,2,5,1,3,4,8,5,2,9,3,10,6,1,9,3,5,3,3,3,9,9,6,2,5,2,4,10,4,10,10,6,3,7,9,4,2,9,7,4,5,3,3,8,2,3,2,9,1,3,3,3,9,5,7,8,8,5,2,8,3,4,2,4,6,3,7,4]scatter_diagram([list(nodes)],nodes)#初始位置分布图#参数d_limit = 150 # 一个区的约束K = math.ceil(sum(demand)/d_limit)  #簇的最小边界#历史最优参数best_s = -1best_center = 0best_clusters = 0best_labels = 0best_clusters_d = 0for n in range(20):#多次遍历,kmeans对初始解敏感#初始化随机生成簇中心index = random.sample(list(range(len(nodes))),K)new_center = [nodes[i] for i in index]i = 1center_list = []while True:#节点——> 簇center = new_center.copy()center_list.append(center)#保留中心,避免出现A生成B,B生成C,C有生成A的情况clusters,cluster_d,label = distribute(center,nodes,K,demand,d_limit)new_center = cal_center(clusters)if (center == new_center) | (new_center in center_list):breaki += 1s = silhouette_score(nodes,label, metric='euclidean') # 计算轮廓系数,聚类的评价指标# scatter_diagram(clusters,nodes)#当前最优图if best_s < s:best_s = sbest_clusters_d = cluster_dbest_center = center.copy()best_clusters = clusters.copy()best_labels = label.copy()scatter_diagram(best_clusters,nodes)#历史最优图# print("各类需求量:",best_clusters_d)

【结果展示】

图1 需求点位置

图2 聚类效果

4 谈论

从结果上看,带约束的聚类效果还是可以的,但是求解过程中会出现图3的聚类效果,蓝色的点距离黄色的点反而更近一点。而且还存在另外一个问题,假设需求量是500,而每簇满足需求的能力是100,理论上最少需要5个簇就可以,但是由于约束的存在和需求不可拆分,可能会导致无法刚好满足五个簇的容量,遇到这种情况我写的算法中是直接报错,虽然这种情况下大概率是出现如图3蓝色点的情况存在,但是也会减小求解最优解的可能性,程序的健壮性较差。

图3 聚类效果

带约束的K-means聚类算法相关推荐

  1. k means聚类算法_一文读懂K-means聚类算法

    1.引言 什么是聚类?我们通常说,机器学习任务可以分为两类,一类是监督学习,一类是无监督学习.监督学习:训练集有明确标签,监督学习就是寻找问题(又称输入.特征.自变量)与标签(又称输出.目标.因变量) ...

  2. k means聚类算法_K-Means 聚类算法 20210108

    说到聚类,应先理解聚类和分类的区别 聚类和分类最大的不同在于:分类的目标是事先已知的,而聚类则不一样,聚类事先不知道目标变量是什么,类别没有像分类那样被预先定义出来. K-Means 聚类算法有很多种 ...

  3. OpenCV官方文档 理解k - means聚类

    理解k - means聚类 目标 在这一章中,我们将了解k - means聚类的概念,它是如何工作等. 理论 我们将这个处理是常用的一个例子. t恤尺寸问题 考虑一个公司要发布一个新模型的t恤. 显然 ...

  4. k均值聚类算法(K Means)及其实战案例

    算法说明 K均值聚类算法其实就是根据距离来看属性,近朱者赤近墨者黑.其中K表示要聚类的数量,就是说样本要被划分成几个类别.而均值则是因为需要求得每个类别的中心点,比如一维样本的中心点一般就是求这些样本 ...

  5. OpenCV的k - means聚类 -对图片进行颜色量化

    OpenCV的k - means聚类 目标 学习使用cv2.kmeans()数据聚类函数OpenCV 理解参数 输入参数 样品:它应该的np.float32数据类型,每个特性应该被放在一个单独的列. ...

  6. k均值聚类算法优缺点_Grasshopper实现K均值聚类算法

    本文很长很长,有很多很多图,包含以下部分: 1.算法简介 2.如何分类平面点 3.如何分类空间点 4.如何分类多维数据 5.后记 提醒:以下内容包括:智障操作,无中生友,重复造轮子 等 1.算法简介 ...

  7. K-Means(K均值聚类算法)

    K-Means(K均值聚类算法) 1.前言 要学习聚类算法就要知道聚类学习算法是什么,为什么要学习聚类学习聚类学习算法,有什么用途,下面就简单的做一下介绍,并且详细的说明k-means均值聚类学习算法 ...

  8. k均值聚类算法python_K均值和其他聚类算法:Python快速入门

    k均值聚类算法python This post was originally published here 这篇文章最初发表在这里 Clustering is the grouping of obje ...

  9. 【模式识别】K均值聚类算法应用实验报告及MATLAB仿真

    一. 实验目的 1.掌握K均值聚类算法的原理和实现过程: 2.掌握K均值聚类算法的应用方法. 二. 实验内容 1.彩色图像分割 选择一幅图像,分别按三种颜色数进行彩色图像分割的结果(原图和分割图).步 ...

  10. K均值聚类算法(HCM,K-Means)

    K均值聚类核心思想如下: 算法把n个向量分为个组,并求每组的聚类中心,使得非相似性(或距离)指标的价值函数(或目标函数)达到最小.当选择欧几里德距离为组j中向量与相应聚类中心间的非相似性指标时,价值函 ...

最新文章

  1. 【Qt】Qt样式表总结(一):选择器
  2. 使用VA助手如何快速添加注释(按doxygen注释规范)
  3. 设置log缓存_带你搞明白什么是缓存穿透、缓存击穿、缓存雪崩
  4. 弹层蒙版(mask),ios滚动穿透,我们项目的解决方案
  5. 四川高职计算机二本线学校,全网首发!四川省本科二批次2019年对口高职投档录取线出炉...
  6. yum提示Another app is currently holding the yum lock; waiting for it to exit...
  7. Java中string中hashcode_为什么String中的Java hashCode()使用31作为乘数?
  8. css常用或不熟悉的
  9. php负载均衡如何获得真实ip,nginx负载均衡后端RS中获取真实ip
  10. Java基础知识——JNI入门介绍
  11. linux getopt_long函数,新手疑问:getopt_long()重入问题
  12. GX Works2使用问题记录
  13. 大学生JAVA程序员周记,java程序员实习周记.docx
  14. 必备浏览器插件,不用安装音乐软件全家桶,轻松下载全网音乐!
  15. 51单片机LED灯闪烁
  16. PHP实现jsapi微信支付
  17. firefox android 去更新,Firefox Android移动版更新
  18. 基于JAVA实现的农夫过河问题
  19. 宝塔服务器面板漏洞-越权访问
  20. 【云原生之Docker实战】使用Docker部署Alist网盘直链程序

热门文章

  1. 数组的length属性和String的length()方法
  2. Thinkpad X200 屏幕备案
  3. 无人机激光雷达的路径规划仿真
  4. c语言打印输出迷宫地图所有路径
  5. 字符串分段组合python123_boost python分段fau
  6. 适用于ios5的应用_适用于设计人员和开发人员的10个很棒的iOS应用
  7. 视频教程-Bootstrap3从基础到案例实战,完美实现响应式网站案例-Bootstrap
  8. canvas -小球自由落体运动
  9. 网上图书订阅系统之(招标书,投标书)
  10. 如何轻松的破解excel 2016工作表密码