k-means聚类算法

开始之前先介绍下什么是簇识别。
簇识别: 簇识别给出聚类结果的含义。假定有一些数据,现在将相似数据归到一起,簇识别会告诉我们这些簇到底都是些什么。
k-均值是发现给定数据集的K个簇的算法。簇个数是用户给定的,每一个簇通过其质心,即簇中所有点的中心来描述。

k-means聚类算法的评价:
优点:容易实现
缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢。
使用数据类型:数值型数据。

工作流程:
首先,随机确定K个初始点作为质心。然后将数据集中的每个点分配到一个簇中,具体来讲,为每个点找距其最近的质心。并将其分配给该质心所对应的簇。这一步完成之后,每个簇的质心更新为该簇所有点的平均值,然后使用心的质心迭代聚类过程,直到收敛为止。
(这里的收敛指质心的不在改变,如果迭代后的质心位置与上一次相比如果超过了设定的差,那么就说明还未收敛,需要继续迭代)

伪代码:
1.创建k个点作为起始质心(经常是随机选择)
2.当任意一个点的簇分配结果发生改变时
        对数据集中的每个数据点
                对每个质心
                        计算质心与数据点之间的距离
                将数据点分配到距其最近的簇
        对每一个簇,计算簇中所有点的均值并将均值作为质心
3.使用新的质心来迭代2,直到收敛为止。
一般流程:
收集数据:使用任意方法
准备数据:需要数值型数据来计算距离,也可以将标称型数据映射为二值型数据再用于距离计算。
分析数据:使用任意方法
训练算法:不适用于无监督学习,即无监督学习没有训练过程。
测试算法:应用聚类算法、观察结果。可以使用量化的错误指标如 误差平方和来评价算法的结果
使用算法:可以用于所希望的任何应用。通常情况下,簇质心可以代表整个簇的数据来做出决定。

其他问题
离群点的处理
离群点可能过度影响簇的发现,导致簇的最终发布会与我们的预想有较大出入,所以提前发现并剔除离群点是有必要的。
利用方差来剔除离群点,结果显示效果非常好。下文java实现的算法并未剔除利群点,如果有需要,可以在自己的算法实现中加入这一步。
簇分裂和簇合并(代码下面会做具体的介绍)
使用较大的K,往往会使得聚类的结果看上去更加合理,但很多情况下,我们并不想增加簇的个数。
这时可以交替采用簇分裂和簇合并。这种方式可以避开局部极小,并且能够得到具有期望个数簇的结果。

代码:
   
   
   
  1. import java.util.ArrayList;
  2. import java.util.EmptyStackException;
  3. import java.util.Random;
  4. import java.util.Scanner;
  5. /**
  6. * Created by wubo on 2016/10/27.
  7. */
  8. public class Kmeans {
  9. private int k;//簇的个数
  10. private int m;// 迭代次数
  11. private int dataSetLength;// 数据集元素个数,即数据集的长度
  12. private ArrayList<float[]> dataSet;// 数据集链表
  13. private ArrayList<float[]> center;// 中心链表
  14. private ArrayList<ArrayList<float[]>> cluster; // 簇
  15. private ArrayList<Float> jc;// 误差平方和,k越接近dataSetLength,误差越小
  16. private Random random;
  17. /**
  18. * 设置需分组的原始数据集
  19. *
  20. * @param dataSet
  21. */
  22. public void setDataSet(ArrayList<float[]> dataSet) {
  23. this.dataSet = dataSet;
  24. }
  25. /**
  26. * 获取结果分组
  27. *
  28. * @return 结果集
  29. */
  30. public ArrayList<ArrayList<float[]>> getCluster() {
  31. return cluster;
  32. }
  33. /**
  34. * 构造函数,传入需要分成的簇数量
  35. *
  36. * @param k
  37. * 簇数量,若k<=0时,设置为1,若k大于数据源的长度时,置为数据源的长度
  38. */
  39. public Kmeans(int k) {
  40. if (k <= 0) {
  41. k = 1;
  42. }
  43. this.k = k;
  44. }
  45. /**
  46. * 初始化
  47. */
  48. private void init() {
  49. m = 0;//初始化迭代次数
  50. random = new Random();
  51. if (dataSet == null || dataSet.size() == 0) {
  52. initDataSet();
  53. }
  54. dataSetLength = dataSet.size();//数据集长度
  55. if (k > dataSetLength) {
  56. k = dataSetLength;
  57. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值