山东大学模式识别实验(java)K-means算法

K-means是无监督学习,也就是说事先并不知道有几类,所有数据都是无标记的,所以虽然本实验的红酒数据集认为应该分为3类,但是对于k-means来说是没有意义的。每次分类前我们首先要人为指定分成K类,然后任意选取K个点作为K个类的中心点,遍历全集,离哪个中心近就认为是哪一堆的。接下来我们要验证所选中心点是否是真正的中心点,计算每一堆各个特征的平均值后得出的就是这一个类的中心,如果与我们认为的中心不同则需要继续计算。以刚才计算出的新中心重新全集遍历分类然后重复上面判断是否完成的过程。最终运算结束,输出真正的中心点。

1.封装的红酒类:

public class Wine {
	private double[] data;

	public double[] getData() {
		return data;
	}

	public void setData(double[] data) {
		this.data = data;
	}
	

}

2.test类:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

public class Test {
	private Wine[] wineCenter;//确定为聚集中心的点
	private List<Wine>[] wineKind;//分类后的点数组
	private int k;
	private List<Wine> wineAll;
	
	public Test(String path){//读取数据文件
		wineAll=new ArrayList<>();
		try {
			BufferedReader reader=new BufferedReader(new FileReader(new File(path)));
			String s=null;
			while((s=reader.readLine())!=null){
				wineAll.add(str2Wine(s.substring(2, s.length())));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void setK(int k){
		this.k=k;
		wineCenter=new Wine[k];
		wineKind=new List[k];
		for (int i = 0; i < k; i++) {
			wineKind[i]=new ArrayList<>();
		}
	}
	
	public Wine str2Wine(String s){
		int start=0;
		int end=0;
		double []data=new double[13];
		Wine wine=new Wine();
		for(int i=0;i<12;i++){
			while(!s.substring(end,end+1).equals(",")){
				end++;
			}
			data[i]=Double.valueOf(s.substring(start,end));
			start=end+1;
			end++;
		}
		data[12]=Double.valueOf(s.substring(start,s.length()));
		wine.setData(data);
		return wine;
	}
	
	public double getDistance(Wine a,Wine b){//计算两个点的欧氏距离,为了方便不开根号
		double result=0;
		double[] d1=a.getData();
		double[] d2=b.getData();
		for (int i = 0; i < 13; i++) {
			double aa=d1[i]-d2[i];
			result+=aa*aa;
		}
		return result;
	}
	
	public void work(){
		int length=wineAll.size();
		int dis=length/k;
		for(int i=0;i<k;i++){
			wineCenter[i]=wineAll.get(dis*i);
		}
		calcu();
		System.out.println("K是:"+k+"\n最终确定的中心点是:");
		for (int i = 0; i < k; i++) {
			double[] dou=wineCenter[i].getData();
			for (int j = 0; j < 13; j++) {
				System.out.print(dou[j]+"   ");
			}
			System.out.println();
		}
	}
	
	private void calcu() {//迭代计算
		boolean finish=true;
		for(int i=0;i<wineAll.size();i++){
			int kind=0;
			double minDis=Double.MAX_VALUE;
			Wine currentWine=wineAll.get(i);
			for (int j = 0; j < k; j++) {
				double currentDis=getDistance(currentWine, wineCenter[j]);
				if (currentDis<minDis) {
					kind=j;
					minDis=currentDis;
				}
			}
			wineKind[kind].add(currentWine);
		}
		for (int i = 0; i < k; i++) {//计算新的聚集中心
			double [] dataNew=new double[13];
			double []dataLast=wineCenter[i].getData();
			for (int p = 0; p < 13; p++) {
				double d=0;
				for (int j = 0; j < wineKind[i].size(); j++) {
					double[] q=wineKind[i].get(j).getData();
					d+=q[p];
				}
				d /=wineKind[i].size();
				dataNew[p]=d;
				if (dataLast[p]!=d) {
					finish=false;
				}
			}
			wineCenter[i].setData(dataNew);
		}
		for (int i = 0; i < k; i++) {
			System.out.println("第"+i+"类的个数是:"+wineKind[i].size());
		}
		if (!finish) {//还没完成中心确定,递归
			wineKind=new List[k];//初始化
			for (int i = 0; i < k; i++) {
				wineKind[i]=new ArrayList<>();
			}
			calcu();
		}
	}

	public static void main(String[]args){
		Test test=new Test("a.txt");
		test.setK(10);
		test.work();
		String s="qwdfwef";
		for (int i = 0; i < args.length; i=i+2) {
			
		}
	}
}

实验结果:



猜你喜欢

转载自blog.csdn.net/zhang___yong/article/details/79053623