【Java】K-means算法Java实现以及图像切割
1.K-means算法简述以及代码原型
数据挖掘中一个重要算法是K-means。我这里就不做具体介绍。假设感兴趣的话能够移步陈皓的博客:
http://www.csdn.net/article/2012-07-03/2807073-k-means 讲得非常好
总的来讲,k-means聚类须要下面几个步骤:
①.初始化数据
②.计算初始的中心点,能够随机选择
③.计算每一个点到每一个聚类中心的距离。而且划分到距离最短的聚类中心簇中
④.计算每一个聚类簇的平均值,这个均值作为新的聚类中心,反复步骤3
⑤.假设达到最大循环或者是聚类中心不再变化或者聚类中心变化幅度小于一定范围时,停止循环。
恩。原理就是这样,超级简单。可是Java算法实现起来代码量并不小。这个代码也不算是全然自己写的啦。也有些借鉴。我把k-means实现封装在了一个类里面,这样就能够随时调用了呢。
import java.util.ArrayList;
import java.util.Random; public class kmeans {
private int k;//簇数
private int m;//迭代次数
private int dataSetLength;//数据集长度
private ArrayList<double[]> dataSet;//数据集合
private ArrayList<double[]> center;//中心链表
private ArrayList<ArrayList<double[]>> cluster;//簇
private ArrayList<Float> jc;//误差平方和,这个是用来计算中心聚点的移动哦
private Random random; //设置原始数据集合
public void setDataSet(ArrayList<double[]> dataSet){
this.dataSet=dataSet;
}
//获得簇分组
public ArrayList<ArrayList<double[]>> getCluster(){
return this.cluster;
}
//构造函数,传入要分的簇的数量
public kmeans(int k){
if(k<=0)
k=1;
this.k=k;
}
//初始化
private void init(){
m=0;
random=new Random();
if(dataSet==null||dataSet.size()==0)
initDataSet();
dataSetLength=dataSet.size();
if(k>dataSetLength)
k=dataSetLength;
center=initCenters();
cluster=initCluster();
jc=new ArrayList<Float>();
}
//初始化数据集合
private void initDataSet(){
dataSet=new ArrayList<double[]>();
double[][] dataSetArray=new double[][]{{8,2},{3,4},{2,5},{4,2},
{7,3},{6,2},{4,7},{6,3},{5,3},{6,3},{6,9},
{1,6},{3,9},{4,1},{8,6}};
for(int i=0;i<dataSetArray.length;i++)
dataSet.add(dataSetArray[i]);
}
//初始化中心链表,分成几簇就有几个中心
private ArrayList<double[]> initCenters(){
ArrayList<double[]> center= new ArrayList<double[]>();
//生成一个随机数列。
int[] randoms=new int[k];
boolean flag;
int temp=random.nextInt(dataSetLength);
randoms[0]=temp;
for(int i=1;i<k;i++){
flag=true;
while(flag){
temp=random.nextInt(dataSetLength);
int j=0;
while(j<i){
if(temp==randoms[j])
break;
j++;
}
if(j==i)
flag=false;
}
randoms[i]=temp;
}
for(int i=0;i<k;i++)
center.add(dataSet.get(randoms[i]));
return center;
}
//初始化簇集合
private ArrayList<ArrayList<double[]>> initCluster(){
ArrayList<ArrayList<double[]>> cluster=
new ArrayList<ArrayList<double[]>>();
for(int i=0;i<k;i++)
cluster.add(new ArrayList<double[]>());
return cluster;
}
//计算距离
private double distance(double[] element,double[] center){
double distance=0.0f;
double x=element[0]-center[0];
double y=element[1]-center[1];
double z=element[2]-center[2];
double sum=x*x+y*y+z*z;
distance=(double)Math.sqrt(sum);
return distance;
}
//计算最短的距离
private int minDistance(double[] distance){
double minDistance=distance[0];
int minLocation=0;
for(int i=0;i<distance.length;i++){
if(distance[i]<minDistance){
minDistance=distance[i];
minLocation=i;
}else if(distance[i]==minDistance){
if(random.nextInt(10)<5){
minLocation=i;
}
}
}
return minLocation;
}
//每一个点分类
private void clusterSet(){
double[] distance=new double[k];
for(int i=0;i<dataSetLength;i++){
//计算到每一个中心店的距离
for(int j=0;j<k;j++)
distance[j]=distance(dataSet.get(i),center.get(j));
//计算最短的距离
int minLocation=minDistance(distance);
//把他加到聚类里
cluster.get(minLocation).add(dataSet.get(i));
}
}
//计算新的中心
private void setNewCenter(){
for(int i=0;i<k;i++){
int n=cluster.get(i).size();
if(n!=0){
double[] newcenter={0,0};
for(int j=0;j<n;j++){
newcenter[0]+=cluster.get(i).get(j)[0];
newcenter[1]+=cluster.get(i).get(j)[1];
}
newcenter[0]=newcenter[0]/n;
newcenter[1]=newcenter[1]/n;
center.set(i, newcenter);
}
}
}
//求2点的误差平方
private double errosquare(double[] element,double[] center){
double x=element[0]-center[0];
double y=element[1]-center[1];
double errosquare=x*x+y*y;
return errosquare;
}
//计算误差平方和准则函数
private void countRule(){
float jcf=0;
for(int i=0;i<cluster.size();i++){
for(int j=0;j<cluster.get(i).size();j++)
jcf+=errosquare(cluster.get(i).get(j),center.get(i));
jc.add(jcf);
}
}
//核心算法
private void Kmeans(){
//初始化各种变量,随机选定中心。初始化聚类
init();
//開始循环
while(true){
//把每一个点分到聚类中去
clusterSet();
//计算目标函数
countRule();
//检查误差变化。由于我规定的计算循环次数为50次,所以就不用计算这个啦。你要愿意用也能够,就是慢一点
/*
if(m!=0){
if(jc.get(m)-jc.get(m-1)==0)
break;
}*/
if(m>=50)
break;
//否则继续生成新的中心
setNewCenter();
m++;
cluster.clear();
cluster=initCluster(); }
}
//仅仅暴露一个接口给外部类
public void execute(){
System.out.print("start kmeans\n");
Kmeans();
System.out.print("kmeans end\n");
}
//用来在外面打印出来已经分好的聚类
public void printDataArray(ArrayList<double[]> data,String dataArrayName){
for(int i=0;i<data.size();i++){
System.out.print("print:"+dataArrayName+"["+i+"]={"+data.get(i)[0]+","+data.get(i)[1]+"}\n");
}
System.out.print("==========================");
}
}
嗯。代码就是这样。凝视写的非常具体,也都能看得懂。
以下我给一个測试样例。
import java.util.ArrayList; public class Test {
public static void main(String[] args){
kmeans k=new kmeans(2);
ArrayList<double[]> dataSet=new ArrayList<double[]>();
dataSet.add(new double[]{2,2,2});
dataSet.add(new double[]{1,2,2});
dataSet.add(new double[]{2,1,2});
dataSet.add(new double[]{1,3,2});
dataSet.add(new double[]{3,1,2});
dataSet.add(new double[]{-2,-2,-2});
dataSet.add(new double[]{-1,-2,-2});
dataSet.add(new double[]{-2,-1,-2});
dataSet.add(new double[]{-3,-1,-2});
dataSet.add(new double[]{-1,-3,-2}); k.setDataSet(dataSet);
k.execute();
ArrayList<ArrayList<double[]>> cluster=k.getCluster();
for(int i=0;i<cluster.size();i++){
k.printDataArray(cluster.get(i), "cluster["+i+"]");
}
}
}
没啥难度,也就是输入写初始数据。然后运行k-means在进行分类。最后打印一下。
这个原型代码非常粗糙。没有加入聚类个数以及循环次数的变量。这些须要自己动手啦。
2.k-means应用图像切割
像这样。
//读取指定文件夹的图片数据,而且写入数组,这个数据要继续处理
private int[][] getImageData(String path){
BufferedImage bi=null;
try{
bi=ImageIO.read(new File(path));
}catch (IOException e){
e.printStackTrace();
}
int width=bi.getWidth();
int height=bi.getHeight();
int [][] data=new int[width][height];
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
data[i][j]=bi.getRGB(i, j);
/*測试输出
for(int i=0;i<data.length;i++)
for(int j=0;j<data[0].length;j++)
System.out.println(data[i][j]);*/
return data;
}
//用来处理获取的像素数据,提取我们须要的写入dataItem数组
private dataItem[][] InitData(int [][] data){
dataItem[][] dataitems=new dataItem[data.length][data[0].length];
for(int i=0;i<data.length;i++){
for(int j=0;j<data[0].length;j++){
dataItem di=new dataItem();
Color c=new Color(data[i][j]);
di.r=(double)c.getRed();
di.g=(double)c.getGreen();
di.b=(double)c.getBlue();
di.group=1;
dataitems[i][j]=di;
}
}
return dataitems;
}
//介货是用来输出图像的
<pre name="code" class="java"> private void ImagedataOut(String path){
Color c0=new Color(255,0,0);
Color c1=new Color(0,255,0);
Color c2=new Color(0,0,255);
Color c3=new Color(128,128,128);
BufferedImage nbi=new BufferedImage(source.length,source[0].length,BufferedImage.TYPE_INT_RGB);
for(int i=0;i<source.length;i++){
for(int j=0;j<source[0].length;j++){
if(source[i][j].group==0)
nbi.setRGB(i, j, c0.getRGB());
else if(source[i][j].group==1)
nbi.setRGB(i, j, c1.getRGB());
else if(source[i][j].group==2)
nbi.setRGB(i, j, c2.getRGB());
else if (source[i][j].group==3)
nbi.setRGB(i, j, c3.getRGB());
//Color c=new Color((int)center[source[i][j].group].r,
// (int)center[source[i][j].group].g,(int)center[source[i][j].group].b);
//nbi.setRGB(i, j, c.getRGB());
}
}
try{
ImageIO.write(nbi, "jpg", new File(path));
}catch(IOException e){
e.printStackTrace();
}
}
非常舒爽。你问我dataItem是啥?等我交完作业我就告诉你。
。所幸鹏鹏改成了double。可是鹏鹏在计算距离的时候又写错了,最后还是机智的胖胖鹏解决掉了全部的bug。
。
等我作业交完就来一次完整的代码解说。
【Java】K-means算法Java实现以及图像切割的更多相关文章
- JAVA分析html算法(JAVA网页蜘蛛算法)
近来有些朋友在做蜘蛛算法,或者在网页上面做深度的数据挖掘.但是遇到复杂而繁琐的html页面大家都望而却步.因为很难获取到相应的数据. 最古老的办法的是尝试用正则表达式,估计那么繁琐的东西得不偿失,浪费 ...
- k近邻算法-java实现
最近在看<机器学习实战>这本书,因为自己本身很想深入的了解机器学习算法,加之想学python,就在朋友的推荐之下选择了这本书进行学习. 一 . K-近邻算法(KNN)概述 最简单最初级的分 ...
- KNN 与 K - Means 算法比较
KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...
- 快速排序算法 java 实现
快速排序算法 java 实现 快速排序算法Java实现 白话经典算法系列之六 快速排序 快速搞定 各种排序算法的分析及java实现 算法概念 快速排序是C.R.A.Hoare于1962年提出的一种划分 ...
- Java数据结构和算法(五)--希尔排序和快速排序
在前面复习了三个简单排序Java数据结构和算法(三)--三大排序--冒泡.选择.插入排序,属于算法的基础,但是效率是偏低的,所以现在 学习高级排序 插入排序存在的问题: 插入排序在逻辑把数据分为两部分 ...
- Java数据结构和算法(一)--栈
栈: 英文名stack,特点是只允许访问最后插入的那个元素,也就是LIFO(后进先出) jdk中的stack源码: public class Stack<E> extends Vector ...
- Java数据结构和算法(六)--二叉树
什么是树? 上面图例就是一个树,用圆代表节点,连接圆的直线代表边.树的顶端总有一个节点,通过它连接第二层的节点,然后第二层连向更下一层的节点,以此递推 ,所以树的顶端小,底部大.和现实中的树是相反的, ...
- k近邻算法的Java实现
k近邻算法是机器学习算法中最简单的算法之一,工作原理是:存在一个样本数据集合,即训练样本集,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据和所属分类的对应关系.输入没有标签的新数据之后, ...
- 新手学,java使用分水岭算法进行图像切割(一)
近期被图像切割整的天昏地暗的,在此感谢老朋友周洋给我关于分水岭算法的指点!本来打算等彩色图像切割有个完满的结果再写这篇文章,可是考虑到到了这一步也算是一个阶段,所以打算对图像切割做一个系列的博文,于是 ...
随机推荐
- PAT 1069 1070 1071 1072
pat 1069 The Black Hole of Numbers 水题,代码如下: #include<cstdio> #include<cstdlib> #include& ...
- Spring-boot加载resources下的文件
加载方式: FileInputStream keyStoreIn = new FileInputStream(ResourceUtils.getFile("classpath:ca/clie ...
- filter中的DelegatingFilterProxy使用事例
最近发现在filter内使用DelegatingFilterProxy过滤内容,那么为什么不用自带的Filter而使用Spring的DelegatingFilterProxy哪?最后才明白是因为fil ...
- stardict dict url
http ://download.huzheng.org/zh_CN/ tar -xjvf a.tar.bz2 -C /usr/share/stardict/dic
- DXL之通过程序修改Domino的设计
Domino R6中,可以将设计元素导出并产生一个DXL(Domino XML)文档,导出以后,我们可以通过程序代码将DXL文档进行修改,再将修改后的代码导入到Domino数据库.这种方式可以修改设计 ...
- .NET 中的 async/await 异步编程
原文出处: Teroy 的博客 前言 最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入的,由于之前对于异步编程不是很了解,所以花费了一些时间学习一下相关 ...
- hibernate 双向 1-n(具体分析)
双向 1-n 与 双向 n-1 是全然同样的两种情形 双向 1-n 须要在 1 的一端能够訪问 n 的一端, 反之依旧. 域模型:从 Order 到 Customer 的多对一双向关联须要在Order ...
- Node.js相关——package概念及NPM
1. package 包 CommonJS的包规范允许我们将一组相关的模块组合到一起,形成一组完整的工具.CommonJS的包规范由 包结构 和 包描述文件 两个部分组成. 1.1 包结构 包实际上就 ...
- ios中第三方库归结
1:uiscrollview 折叠 展开中不包含tablecell. 展开列表效果 Collapse Click () https://github.com/bennyguitar/Collapse ...
- ios 中UIViewController的分类
#import <UIKit/UIKit.h> #define TOPVIEWTAG 0x10000 // 导航栏的图片 @interface UIViewController (Chnb ...