栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java运用kmeans算法进行聚类

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java运用kmeans算法进行聚类

java运用kmeans算法进行聚类

文章目录
    • java运用kmeans算法进行聚类
  • 一、Kmeans算法使用步骤
  • 二、Java实现
    • 1.准备工作
      • 误差平方和的计算
      • 需要用到的数据集
      • 工具:eclipse及效果图演示
    • 2.代码
    • 3.使用weka验证
  • 三、源码


一、Kmeans算法使用步骤
  1. 选出k值,随机出k个簇的中心点。

  2. 分别计算每个点和k个中心点之间的欧式距离,就近归类。

    欧式距离计算方法如下:

  3. 最终中心点集可以划分为k类,分别重新计算每类中新的中心点。

    重新计算的中心点坐标即把当前簇内所有点的x,y坐标分别加起来取平均值

  4. 重复2,3步骤对所有点进行归类,如果当所有分类的质心点不再改变,则最终收敛。

二、Java实现

java代码参考这篇文章为了满足老师作业的要求进行了一定程度的添加和修改(主要改进在于对计算过程进行了记录以及后续误差平方和的计算)

1.准备工作 误差平方和的计算

需要用到的数据集

(我们在java代码导入数据集时需要先新建一个txt文件)

工具:eclipse及效果图演示

先看效果图:(首先导入文件,然后点击按钮后会显示每次迭代结果和sse,sse越小说明迭代效果越好)

2.代码

代码如下:
定义一个类表示每个点·的坐标

class Point{
	String name;
	double x,y;

	public Point(String name,double x,double y){
		this.name=name;
		this.x=x;
		this.y=y;
	}
	public Point(){
	}

 //计算两个坐标点之间的欧式距离
	public static double distance(Point a,Point b){
		return Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
	}
	
//计算两个坐标点之间距离的平方
	public static double squaredistance(Point a,Point b){
		return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
	}
	
 //计算每个坐标点距离哪个簇最近
	public static int ClusterDistance(Point p,ArrayList array){
        int a=0;
		for(int i=0;iPoint.distance(p, array.get(i).center)){
				a=i;
			}
		}
		return a;	
	}
   public static void PointAdd(ArrayList PointArray,  ArrayList DoubleArray){
	  for(int i=0;i 

定义一个类表示每个簇

 //定义一个类用于表示簇
class Cluster{
	
	 
	 Point center=new Point();//簇中心点
	 ArrayList Array=new ArrayList();	//簇中的坐标元素
	 boolean changed=true;//用于判断该簇的中心点坐标是否发生变化
	
 public Cluster(double x,double y){
	 center.x=x;
	 center.y=y;
 }
 //计算簇的新中心点坐标
 public static void NewCenter(Cluster cluster){
	  double sumx=0,sumy=0;
	  int i=0;
	  for(Point ex:cluster.Array){
		  sumx+=ex.x;
		  sumy+=ex.y;
		  i++;
	  }
	 if(cluster.center.x!=sumx/i||cluster.center.y!=sumy/i){
	 cluster.center.x=sumx/i;
	 cluster.center.y=sumy/i;
	 cluster.changed=true;
	 }
	 else if(cluster.center.x==sumx/i&&cluster.center.y==sumy/i){
		 cluster.changed=false;
	 }
 }
//判断所有簇的中心点是否不再发生变化
 public static boolean Changing(ArrayList array){
	 boolean ex=false;
	 for(Cluster e:array){
		 if(e.changed==true){
			 ex=true;
		 }
	 }
	 return ex;
	 	 
 }
 

}

随机选择初始簇中心的类

//用于获取1~n之间的t个不重复的整数
class GetRandom{
	@SuppressWarnings("unchecked")
	static public int[] fn(int n,int t)
	{
	    ArrayList numbers=new ArrayList();
	    int[] rtnumbers=new int[t];
	    for(int i=0;i 

另外定义一个类来声明需要使用到的全局变量

class Pub{
	static StringBuffer str=new StringBuffer();//存放textarea的内容
	static StringBuffer str1=new StringBuffer();//存放textarea1的内容
	static ArrayList TotalArray=new ArrayList();  //定义用于存放坐标点的泛型数组
	static ArrayList ClusterArray=new ArrayList();   //定义用于存放各个簇的点的泛型数组
	static ArrayList ColorArray=new ArrayList();
}

绘制可视化窗口相关代码

class Drawframe extends Jframe
{

	private JFileChooser chooser=new JFileChooser();
    Jtextarea textarea=new Jtextarea();
    Jtextarea textarea1=new Jtextarea();
    JTextField testField=new JTextField(5);
	
   public Drawframe()
   {
      setTitle("Kmeans");
      setSize(700,700);
      setLayout(null);
      //-----------Menu---------------/
      JMenuBar menuBar=new JMenuBar();//菜单栏
      setJMenuBar(menuBar);
      JMenu openMenu=new JMenu("File");//菜单对象
      menuBar.add(openMenu);
      JMenuItem FileOpen=new JMenuItem("Open File..."); //菜单项
      openMenu.add(FileOpen);
      FileOpen.addActionListener(new FileOpenListener());
      //---------TitlePanel-----------/
      JLabel TitleLabel=new JLabel("k-means聚类算法模拟");
      TitleLabel.setFont(new Font("Dialog",1,22));
      add(TitleLabel);
      TitleLabel.setBounds(250, -10, 300, 60);
      //----------kPanel--------------/
      JPanel kPanel=new JPanel();
      JLabel label=new JLabel("请输入k值(必须为整数且不大于数据集中点的个数):");
    //  JLabel label=new JLabel("请输入k值(必须为整数)(1<=k" + Pub.ClusterArray.size() + "):");
      JButton testButton=new JButton("开始模拟");
      testButton.addActionListener(new ButtonListener());
      kPanel.add(label);
      kPanel.add(testField);
      kPanel.add(testButton);
      add(kPanel);
      kPanel.setBounds(80,50,500,35);
    //-----------textPanel1--------------/
      JScrollPane scrollPane=new JScrollPane(textarea);
      add(scrollPane);
      scrollPane.setBounds(350,100,300,400);
    //-----------textPanel2--------------/
      JScrollPane scrollPane2=new JScrollPane(textarea1);
      add(scrollPane2);
      scrollPane2.setBounds(60,100,250,400);
      
   }

文件及测试按钮的监听

   //选择文件监听事件
   private class FileOpenListener implements ActionListener{
	   public void actionPerformed(ActionEvent event){
		   chooser.setCurrentDirectory(new File("D://"));
		   int result=chooser.showOpenDialog(Drawframe.this);
		   if(result==JFileChooser.APPROVE_OPTION){
			   String FilePath=chooser.getSelectedFile().getPath();
			   ArrayList test=new takenumber().getPoint(FilePath);
			   //先把以前点集中的数据清空
			   Pub.TotalArray.clear();
               new Point().PointAdd(Pub.TotalArray, test);
               //把str1中存的字符串清空
			  Pub.str1.delete(0, Pub.str1.length());
			  //把从文件中获取的点坐标转化为字符串
			  for(Point ex:Pub.TotalArray){
				  Pub.str1.append(" "+ex.name+" ("+ex.x+","+ex.y+")n");
			  }
			  textarea1.setText(Pub.str1.toString());
			  textarea1.setFont(new Font("Serif",0,16));
			  textarea.setText("");
			  textarea.setEditable(false);
			  textarea1.setEditable(false);
			  Pub.ClusterArray.clear();
		   }
		   
	   }  
   }
 
   //测试按钮监听事件 
   private class ButtonListener implements ActionListener{
	   public void actionPerformed(ActionEvent event){
		   if(testField.getText().equals("")||Integer.parseInt(testField.getText())==0){
			   Pub.str.append("k值不能为空或者为0!请输入一个值!");
			   textarea.setText(Pub.str.toString());
				Pub.str.delete(0, Pub.str.length());
		   }
		   else if(Integer.parseInt(testField.getText())>Pub.TotalArray.size()){
			   Pub.str.append("请输入正确的k值!");
			   textarea.setText(Pub.str.toString());
			 //  textarea.setText(String.valueOf(Pub.TotalArray.size()));
				Pub.str.delete(0, Pub.str.length());
				System.out.print(Pub.ClusterArray.size());
		   }
		   else{
		   int k=Integer.parseInt(testField.getText());
			//在所有元素的数组里随机选择k个坐标点用于代表初始簇中心
			int ramdon[]=new GetRandom().fn(Pub.TotalArray.size(), k);
			Pub.ClusterArray.clear();
			
			//将随机选择的点加入到簇中
			for(int i=0;i PointArray=new ArrayList();//用于存放要删除的点的数组
			while(Cluster.Changing(Pub.ClusterArray)!=false){
				  Pub.str.append("第"+(m++)+"次迭代的结果为:n");
				    int ii=1;
				    
				    for(int i = 1; i <= Pub.ClusterArray.size(); i++) {
				    	Pub.str.append("              "+"C"+i+"("+String.format("%.3f", Pub.ClusterArray.get(i-1).center.x)+","+String.format("%.3f", Pub.ClusterArray.get(i-1).center.y)+")"+ "   ");
				    }
				    Pub.str.append("n");

				    for(int i = 0; i < Pub.TotalArray.size(); i++) {
				    	Point point1 = Pub.TotalArray.get(i);
				    	Pub.str.append("("+ String.format("%.2f",point1.x)+","+String.format("%.2f",point1.y)+")");
				    	
				    	for(int j=0; j 

还有一个从文件中获取数据时需要用到的类:

public class takenumber {
   public static void main(String args[]){
   }
   public ArrayList getPoint(String path){
	   File filePath = new File(path);
		Scanner scanner;
		try {
			scanner = new Scanner(filePath);
			ArrayList StringArray=new ArrayList();
			while(scanner.hasNextLine()){
				StringArray.add(scanner.nextLine());
			}
			scanner.close();
		    ArrayList DoubleArray=new ArrayList();
		    for(int i=0;i 
3.使用weka验证 

为了验证结果的准确性,我又使用weka进行了依次计算,得到了一个与我计算相同的结果
(weka聚类时初始点也是随机的,我们可以通过改变seed值改变初始随机点)

三、源码

源文件如下链接

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/445704.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号