K-Means聚类算法

更多数据挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm

算法介绍

K-Means又名为K均值算法,他是一个聚类算法,这里的K就是聚簇中心的个数,代表数据中存在多少数据簇。K-Means在聚类算法中算是非常简单的一个算法了。有点类似于KNN算法,都用到了距离矢量度量,用欧式距离作为小分类的标准。

算法步骤

(1)、设定数字k,从n个初始数据中随机的设置k个点为聚类中心点。

(2)、针对n个点的每个数据点,遍历计算到k个聚类中心点的距离,最后按照离哪个中心点最近,就划分到那个类别中。

(3)、对每个已经划分好类别的n个点,对同个类别的点求均值,作为此类别新的中心点。

(4)、循环(2),(3)直到最终中心点收敛。

以上的计算过程将会在下面我的程序实现中有所体现。

算法的代码实现

输入数据:

  1. 33
  2. 410
  3. 96
  4. 148
  5. 1811
  6. 217
主实现类:

  1. packageDataMining_KMeans;
  2. importjava.io.BufferedReader;
  3. importjava.io.File;
  4. importjava.io.FileReader;
  5. importjava.io.IOException;
  6. importjava.text.MessageFormat;
  7. importjava.util.ArrayList;
  8. importjava.util.Collections;
  9. /**
  10. *k均值算法工具类
  11. *
  12. *@authorlyq
  13. *
  14. */
  15. publicclassKMeansTool{
  16. //输入数据文件地址
  17. privateStringfilePath;
  18. //分类类别个数
  19. privateintclassNum;
  20. //类名称
  21. privateArrayList<String>classNames;
  22. //聚类坐标点
  23. privateArrayList<Point>classPoints;
  24. //所有的数据左边点
  25. privateArrayList<Point>totalPoints;
  26. publicKMeansTool(StringfilePath,intclassNum){
  27. this.filePath=filePath;
  28. this.classNum=classNum;
  29. readDataFile();
  30. }
  31. /**
  32. *从文件中读取数据
  33. */
  34. privatevoidreadDataFile(){
  35. Filefile=newFile(filePath);
  36. ArrayList<String[]>dataArray=newArrayList<String[]>();
  37. try{
  38. BufferedReaderin=newBufferedReader(newFileReader(file));
  39. Stringstr;
  40. String[]tempArray;
  41. while((str=in.readLine())!=null){
  42. tempArray=str.split("");
  43. dataArray.add(tempArray);
  44. }
  45. in.close();
  46. }catch(IOExceptione){
  47. e.getStackTrace();
  48. }
  49. classPoints=newArrayList<>();
  50. totalPoints=newArrayList<>();
  51. classNames=newArrayList<>();
  52. for(inti=0,j=1;i<dataArray.size();i++){
  53. if(j<=classNum){
  54. classPoints.add(newPoint(dataArray.get(i)[0],
  55. dataArray.get(i)[1],j+""));
  56. classNames.add(i+"");
  57. j++;
  58. }
  59. totalPoints
  60. .add(newPoint(dataArray.get(i)[0],dataArray.get(i)[1]));
  61. }
  62. }
  63. /**
  64. *K均值聚类算法实现
  65. */
  66. publicvoidkMeansClustering(){
  67. doubletempX=0;
  68. doubletempY=0;
  69. intcount=0;
  70. doubleerror=Integer.MAX_VALUE;
  71. Pointtemp;
  72. while(error>0.01*classNum){
  73. for(Pointp1:totalPoints){
  74. //将所有的测试坐标点就近分类
  75. for(Pointp2:classPoints){
  76. p2.computerDistance(p1);
  77. }
  78. Collections.sort(classPoints);
  79. //取出p1离类坐标点最近的那个点
  80. p1.setClassName(classPoints.get(0).getClassName());
  81. }
  82. error=0;
  83. //按照均值重新划分聚类中心点
  84. for(Pointp1:classPoints){
  85. count=0;
  86. tempX=0;
  87. tempY=0;
  88. for(Pointp:totalPoints){
  89. if(p.getClassName().equals(p1.getClassName())){
  90. count++;
  91. tempX+=p.getX();
  92. tempY+=p.getY();
  93. }
  94. }
  95. tempX/=count;
  96. tempY/=count;
  97. error+=Math.abs((tempX-p1.getX()));
  98. error+=Math.abs((tempY-p1.getY()));
  99. //计算均值
  100. p1.setX(tempX);
  101. p1.setY(tempY);
  102. }
  103. for(inti=0;i<classPoints.size();i++){
  104. temp=classPoints.get(i);
  105. System.out.println(MessageFormat.format("聚类中心点{0},x={1},y={2}",
  106. (i+1),temp.getX(),temp.getY()));
  107. }
  108. System.out.println("----------");
  109. }
  110. System.out.println("结果值收敛");
  111. for(inti=0;i<classPoints.size();i++){
  112. temp=classPoints.get(i);
  113. System.out.println(MessageFormat.format("聚类中心点{0},x={1},y={2}",
  114. (i+1),temp.getX(),temp.getY()));
  115. }
  116. }
  117. }
坐标点类:

  1. packageDataMining_KMeans;
  2. /**
  3. *坐标点类
  4. *
  5. *@authorlyq
  6. *
  7. */
  8. publicclassPointimplementsComparable<Point>{
  9. //坐标点横坐标
  10. privatedoublex;
  11. //坐标点纵坐标
  12. privatedoubley;
  13. //以此点作为聚类中心的类的类名称
  14. privateStringclassName;
  15. //坐标点之间的欧式距离
  16. privateDoubledistance;
  17. publicPoint(doublex,doubley){
  18. this.x=x;
  19. this.y=y;
  20. }
  21. publicPoint(Stringx,Stringy){
  22. this.x=Double.parseDouble(x);
  23. this.y=Double.parseDouble(y);
  24. }
  25. publicPoint(Stringx,Stringy,StringclassName){
  26. this.x=Double.parseDouble(x);
  27. this.y=Double.parseDouble(y);
  28. this.className=className;
  29. }
  30. /**
  31. *距离目标点p的欧几里得距离
  32. *
  33. *@paramp
  34. */
  35. publicvoidcomputerDistance(Pointp){
  36. if(p==null){
  37. return;
  38. }
  39. this.distance=(this.x-p.x)*(this.x-p.x)+(this.y-p.y)
  40. *(this.y-p.y);
  41. }
  42. publicdoublegetX(){
  43. returnx;
  44. }
  45. publicvoidsetX(doublex){
  46. this.x=x;
  47. }
  48. publicdoublegetY(){
  49. returny;
  50. }
  51. publicvoidsetY(doubley){
  52. this.y=y;
  53. }
  54. publicStringgetClassName(){
  55. returnclassName;
  56. }
  57. publicvoidsetClassName(StringclassName){
  58. this.className=className;
  59. }
  60. publicdoublegetDistance(){
  61. returndistance;
  62. }
  63. publicvoidsetDistance(doubledistance){
  64. this.distance=distance;
  65. }
  66. @Override
  67. publicintcompareTo(Pointo){
  68. //TODOAuto-generatedmethodstub
  69. returnthis.distance.compareTo(o.distance);
  70. }
  71. }
调用类:

  1. /**
  2. *K-means(K均值)算法调用类
  3. *@authorlyq
  4. *
  5. */
  6. publicclassClient{
  7. publicstaticvoidmain(String[]args){
  8. StringfilePath="C:\\Users\\lyq\\Desktop\\icon\\input.txt";
  9. //聚类中心数量设定
  10. intclassNum=3;
  11. KMeansTooltool=newKMeansTool(filePath,classNum);
  12. tool.kMeansClustering();
  13. }
  14. }

测试输出结果:

  1. 聚类中心点1,x=15.5,y=8
  2. 聚类中心点2,x=4,y=10
  3. 聚类中心点3,x=3,y=3
  4. ----------
  5. 聚类中心点1,x=17.667,y=8.667
  6. 聚类中心点2,x=6.5,y=8
  7. 聚类中心点3,x=3,y=3
  8. ----------
  9. 聚类中心点1,x=17.667,y=8.667
  10. 聚类中心点2,x=6.5,y=8
  11. 聚类中心点3,x=3,y=3
  12. ----------
  13. 结果值收敛
  14. 聚类中心点1,x=17.667,y=8.667
  15. 聚类中心点2,x=6.5,y=8
  16. 聚类中心点3,x=3,y=3

K-Means算法的优缺点

1、首先优点当然是算法简单,快速,易懂,没有涉及到特别复杂的数据结构。

2、缺点1是最开始K的数量值以及K个聚类中心点的设置不好定,往往开始时不同的k个中心点的设置对后面迭代计算的走势会有比较大的影响,这时候可以考虑根据类的自动合并和分裂来确定这个k。

3、缺点2由于计算是迭代式的,而且计算距离的时候需要完全遍历一遍中心点,当数据规模比较大的时候,开销就显得比较大了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值