K-means算法是硬聚类算法,是典型的基于原型的目标函数聚类方法的代表,它是数据点到原型的某种距离作为优化的目标函数,利用函数求极值的方法得到迭代运算的调整规则。K-means算法以欧式距离作为相似度测度,它是求对应某一初始聚类中心向量V最优分类,使得评价指标J最小。算法采用误差平方和准则函数作为聚类准则函数。

package com.coshaho.learn.kmeans;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList; public class KMeans
{
//聚类的数目
final static int ClassCount = 3;
//样本数目(测试集)
final static int InstanceNumber = 150;
//样本属性数目(测试)
final static int FieldCount = 5; //设置异常点阈值参数(每一类初始的最小数目为InstanceNumber/ClassCount^t)
final static double t = 2.0; //存放数据的矩阵
private float[][] data;
//每个类的均值中心
private float[][] classData;
//噪声集合索引
private ArrayList<Integer> noises;
//存放每次变换结果的矩阵
private ArrayList<ArrayList<Integer>> result; public KMeans()
{
//最后一位用来储存结果
data = new float[InstanceNumber][FieldCount+1];
classData = new float[ClassCount][FieldCount];
result = new ArrayList<ArrayList<Integer>>(ClassCount);
noises = new ArrayList<Integer>();
} public void readData(String TrainDataFile)
{
FileReader fr = null;
BufferedReader br = null;
try
{
fr = new FileReader(TrainDataFile);
br = new BufferedReader(fr);
//存放数据的临时变量
String lineData = null;
String[] splitData = null;
int line = 0;
while( br.ready())
{
lineData = br.readLine();
System.out.println(lineData);
splitData = lineData.split(",");
for(int i = 0 ; i < splitData.length ;i++)
{
data[line][i] = Float.parseFloat(splitData[i]);
}
line++;
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(null != br)
{
try
{
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
if(null != fr)
{
try
{
fr.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
} public void cluster()
{
//数据归一化
normalize(); //标记是否需要重新找初始点
boolean needUpdataInitials = true; //找初始点的迭代次数
int times = 1; //找初始点
while(needUpdataInitials)
{
needUpdataInitials = false;
result.clear();
System.out.println("Find Initials Iteration"+(times++)+"time(s)"); //一次找初始点的尝试和根据初始点的分类
findInitials();
firstClassify(); for(int i = 0;i < result.size();i++)
{
if(result.get(i).size() < InstanceNumber/Math.pow(ClassCount,t))
{
needUpdataInitials = true;
noises.addAll(result.get(i));
}
}
} Adjust();
} /**
* 数据归一化
* @author coshaho
*/
private void normalize()
{
// 计算数据每个维度最大值max
float[] max = new float[FieldCount];
for(int i = 0;i < InstanceNumber;i++)
{
for(int j = 0;j < FieldCount;j++)
{
if(data[i][j] > max[j])
{
max[j] = data[i][j];
}
}
} // 每个维度归一化值=原始值/max
for(int i = 0;i < InstanceNumber;i++)
{
for(int j = 0;j < FieldCount;j++)
{
data[i][j] = data[i][j]/max[j];
}
}
} /**
* 寻找初始聚类中心
* @author coshaho
*/
private void findInitials()
{
int i, j, a, b;
i = j = a = b = 0;
float maxDis = 0;
int alreadyCls = 2; // 选取距离最远的两个点a,b作为聚类中心点
ArrayList<Integer> initials = new ArrayList<Integer>();
for (; i < InstanceNumber; i++)
{
// 噪声点不参与计算
if (noises.contains(i))
{
continue;
}
j = i + 1;
for (; j < InstanceNumber; j++)
{
// 噪声点不参与计算
if (noises.contains(j))
{
continue;
}
float newDis = calDis(data[i], data[j]);
if (maxDis < newDis)
{
a = i;
b = j;
maxDis = newDis;
}
}
} // initials添加初始聚类中心点序号a,b
initials.add(a);
initials.add(b); // classData添加聚类中心点data[a],data[b]
classData[0] = data[a];
classData[1] = data[b]; // 新增两个聚类,并添加聚类成员
ArrayList<Integer> resultOne = new ArrayList<Integer>();
ArrayList<Integer> resultTwo = new ArrayList<Integer>();
resultOne.add(a);
resultTwo.add(b);
result.add(resultOne);
result.add(resultTwo); // 1、计算剩下每个点x与其他点的最小距离l,并记录Map<x,l>
// 2、选取Map<x,l>中的最大l,并以对应的点x作为新的聚类中心
while (alreadyCls < ClassCount)
{
i = j = 0;
float maxMin = 0;
int newClass = -1; for (; i < InstanceNumber; i++)
{
float min = 0;
float newMin = 0;
if (initials.contains(i))
{
continue;
}
if (noises.contains(i))
{
continue;
}
for (j = 0; j < alreadyCls; j++)
{
newMin = calDis(data[i], classData[j]);
if (min == 0 || newMin < min)
{
min = newMin;
}
}
if (min > maxMin)
{
maxMin = min;
newClass = i;
}
} // initials添加新的聚类中心点序号newClass
initials.add(newClass); // classData添加新的聚类中心点data[newClass]
classData[alreadyCls++] = data[newClass]; // 新增一个聚类,并添加成员
ArrayList<Integer> rslt = new ArrayList<Integer>();
rslt.add(newClass);
result.add(rslt);
}
} /**
* 首次聚类分配
* 点x到哪个聚类中心点最近,则划分到哪个聚类
* @author coshaho
*/
public void firstClassify()
{
for (int i = 0; i < InstanceNumber; i++)
{
float min = 0f;
int clsId = -1;
for (int j = 0; j < classData.length; j++)
{
// 欧式距离
float newMin = calDis(classData[j], data[i]);
if (clsId == -1 || newMin < min)
{
clsId = j;
min = newMin;
}
} if (!result.get(clsId).contains(i))
{
result.get(clsId).add(i);
}
}
} // 迭代分类,直到各个类的数据不再变化
public void Adjust()
{
// 记录是否发生变化
boolean change = true; // 循环的次数
int times = 1;
while (change)
{
// 复位
change = false;
System.out.println("Adjust Iteration" + (times++) + "time(s)"); // 重新计算每个类的均值
for (int i = 0; i < ClassCount; i++)
{
// 原有的数据
ArrayList<Integer> cls = result.get(i); // 新的均值
float[] newMean = new float[FieldCount]; // 计算均值
for (Integer index : cls)
{
for (int j = 0; j < FieldCount; j++)
newMean[j] += data[index][j];
}
for (int j = 0; j < FieldCount; j++)
{
newMean[j] /= cls.size();
}
if (!compareMean(newMean, classData[i]))
{
classData[i] = newMean;
change = true;
}
}
// 清空之前的数据
for (ArrayList<Integer> cls : result)
{
cls.clear();
} // 重新分配
for (int i = 0; i < InstanceNumber; i++)
{
float min = 0f;
int clsId = -1;
for (int j = 0; j < classData.length; j++)
{
float newMin = calDis(classData[j], data[i]);
if (clsId == -1 || newMin < min)
{
clsId = j;
min = newMin;
}
}
data[i][FieldCount] = clsId;
result.get(clsId).add(i);
}
}
} /**
* 计算a样本和b样本的欧式距离作为不相似度
*
* @param a 样本a
* @param b 样本b
* @return 欧式距离长度
*/
private float calDis(float[] aVector, float[] bVector) {
double dis = 0;
int i = 0;
/* 最后一个数据在训练集中为结果,所以不考虑 */
for (; i < aVector.length; i++)
dis += Math.pow(bVector[i] - aVector[i], 2);
dis = Math.pow(dis, 0.5);
return (float) dis;
} /**
* 判断两个均值向量是否相等
*
* @param a 向量a
* @param b 向量b
* @return
*/
private boolean compareMean(float[] a, float[] b) {
if (a.length != b.length)
return false;
for (int i = 0; i < a.length; i++) {
if (a[i] > 0 && b[i] > 0 && a[i] != b[i]) {
return false;
}
}
return true;
} /**
* 将结果输出到一个文件中
*
* @param fileName
*/
public void printResult(String fileName)
{
FileWriter fw = null;
BufferedWriter bw = null;
try
{
fw = new FileWriter(fileName);
bw = new BufferedWriter(fw);
// 写入文件
for (int i = 0; i < InstanceNumber; i++)
{
bw.write(String.valueOf(data[i][FieldCount]).substring(0, 1));
bw.newLine();
} // 统计每类的数目,打印到控制台
for (int i = 0; i < ClassCount; i++)
{
System.out.println("第" + (i + 1) + "类数目: "
+ result.get(i).size());
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{ // 关闭资源
if (bw != null)
{
try
{
bw.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
if (fw != null)
{
try
{
fw.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}

K-Means算法的Java实现的更多相关文章

  1. k近邻算法的Java实现

    k近邻算法是机器学习算法中最简单的算法之一,工作原理是:存在一个样本数据集合,即训练样本集,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据和所属分类的对应关系.输入没有标签的新数据之后, ...

  2. KNN 与 K - Means 算法比较

    KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...

  3. K-means算法

    K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢?  ...

  4. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  5. 常见排序算法(附java代码)

    常见排序算法与java实现 一.选择排序(SelectSort) 基本原理:对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换:接着对不包括第一个记录以外的其他 ...

  6. 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,循环控制及其优化

    上两篇博客 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现 研究了递归方法实现回溯,解决N皇后问题,下面我们来 ...

  7. 【LeetCode-面试算法经典-Java实现】【053-Maximum Subarray(最大子数组和)】

    [053-Maximum Subarray(最大子数组和)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Find the contiguous subarray w ...

  8. 【LeetCode-面试算法经典-Java实现】【059-Spiral Matrix II(螺旋矩阵II)】

    [059-Spiral Matrix II(螺旋矩阵II)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given an integer n, generate a ...

  9. 对一致性Hash算法及java实现(转)

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  10. 对一致性Hash算法,Java代码实现的深入研究(转)

    转载:http://www.cnblogs.com/xrq730/p/5186728.html 一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读 ...

随机推荐

  1. Python中的下划线(转)

    译文原文:https://segmentfault.com/a/1190000002611411 原文地址这篇文章讨论Python中下划线_的使用.跟Python中很多用法类似,下划线_的不同用法绝大 ...

  2. oracle闪回的使用

    1.闪回查询(原理:依赖于UNDO表空间)查询当前SCN号select current_scn from v$database;误删数据以后select * from table_name as of ...

  3. 如何快速REPAIR TABLE

    早上到公司,刚准备吃早餐,手机响了,一看是服务器自动重启了.好吧,准备修复数据吧.游戏服的游戏日志使用的是MyISAM.众所周知,MyISAM表在服务器意外宕机或者mysqld进程挂掉以后,MyISA ...

  4. 如何在Digital Ocean上申请服务器的教程

    本文会详细叙述如何在digital ocean上注册.申请.创建以及配置服务器,亲测有效. what's the Digital Ocean ? 根据度娘释义,Digital Ocean是digita ...

  5. dxCalloutPopup 简单使用教程

    Panel1.Visible := False; // 设置panel初始不显示 dxCalloutPopup1.PopupControl := Panel1; // 设置弹出窗口内容为哪个控件 dx ...

  6. 前端框架之Vue(6)-列表渲染

    用v-for把一个数组对应为一组元素 我们用 v-for 指令根据一组数组的选项列表进行渲染. v-for 指令需要使用 item in items 形式的特殊语法, items 是源数据数组并且 i ...

  7. element-dialog封装成子组件

    1.父组件 <template> <card-layout :title="L('Users')" :actions="actions" @c ...

  8. vue 刷新当前页面

    情景: 比如在删除或者增加一条记录的时候希望当前页面可以重新刷新 请求接口中直接将数组结果取第0个数组或者第n个数组给变量,会报错 0 的错误,此时多次刷新即可 方法一.这种方法简单快捷,但是页面会有 ...

  9. Mac charles 抓取https请求,安装证书后还是显示unknown

    https://blog.csdn.net/qq_23114525/article/details/81460840 1. 配置证书 2. 设置钥匙串信任 3. 设置手机代理 端口号需要对应设置的端口 ...

  10. LuaFileSystem

    bokeyuan_1234 lua的文件管理 lua没有自己的文件管理 只有读取和写入文件,但是可以通过调用lfs(LuaFileSystem),lfs是一个 用于lua进行文件访问的库,支持lua5 ...