kmeans聚类源代码
代码是在weka上二次开发的,但没有使用原来的kmeans代码,只是用了它的数据类Intances,先说下与它相关的几点东西。
一、KMeans算法简介
输入:聚类个数k,以及包含 n个数据对象的数据库。
输出:满足方差最小标准的k个聚类。
处理流程:
(1)从 n个数据对象任意选择 k 个对象作为初始聚类中心.
(2)根据每个聚类对象的均值(中心对象),计算每个对象与这些中心对象的距离;并根据最小距离重新对相应对象进行划分;
(3)重新计算每个(有变化)的聚类的均值。
(4)重复(2)(3),直到聚类不发生改变。
划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。
k-means 算法的工作过程说明如下:首先从n个数据对象任意选择 k 个对象作为初始聚类中心;而对于所剩下其它对象,则根据它们与这些聚类中心的相似度(距离),分别将它们分配给与其最相似的(聚类中心所代表的)聚类;然后再计算每个所获新聚类的聚类中心(该聚类中所有对象的均值);不断重复这一过程直到标准测度函数开始收敛为止。一般都采用均方差作为标准测度函数. k个聚类具有以下特点:各聚类本身尽可能的紧凑,而各聚类之间尽可能的分开。
二、weka相关介绍
1、Instances
Instances是数据集类,是样本或实例的集合。
Instances有个数据头header,包含除了样本Instance之外的信息,比如attributes的信息。
//data是Instances类型
Instances ins = new Instances(data, 0);
//用data的数据集信息创建一个新的Instances类,但不包含data的样本
2、Instance
Instance是一个接口,对应的是一个样本或实例。
因为不同项目中数据集是不一样的,也就不能固定Instance的具体属性,所以写成接口。在自己的项目中,应该实现这个Instance
3、Attribute
属性类,对应Instance的一列。
每个Attribute保存的是Instance这一列可取的值。
a、如果是属性是数值类型,这个Attribute就用Numeric类型表示
b、如果是String类型,这个Attribute保存了一个向量,向量的每个值是属性可以取到的String值。
所以,Attribute不保存某个Instance的某个属性状态,而是数据集Instances的某个属性的可取范围,也就是这个属性的值域。
所以,虽然Instance能get到某个Attribute,当不能直接从这个Attribute获取这个属性值。属性值可以直接从Instance获取。
//获取第i个属性的值,用String表示
instance.toString(i)
如果属性值是数值类型,可以直接获取,不用toString(i)
//获取第3个属性的值,从0开始计数。返回double
instance.value(3)
4、InstanceQuery
我的数据是在数据库中,所以我就用InstanceQuery这个类,而且可以避免我自己去实现Instance类。
可以参考下官方文档:http://weka.wikispaces.com/Use+WEKA+in+your+Java+code
首先要修改DatabaseUtils.props文档,在weka.experiment包下面。
在Eclipse IDE下没法直接修改,我用2345好压找到文件,修改了保存回去,就ok了。我连的是oracle。
主要是修改DatabaseUtils.props的这两行:
# JDBC driver (comma-separated list)
jdbcDriver=oracle.jdbc.driver.OracleDriver # database URL
jdbcURL=jdbc:oracle:thin:@192.168.2.67:1521:orcl
然后就是在代码中写了:
public static Instances getData() throws Exception {
InstanceQuery query = getQuery();
String sql = "..............................................................";
Instances data = query.retrieveInstances(sql);
if (data.numInstances() <= 0)
throw new Exception("data size is 0;");
clusterCentroids = new Instances(data, numClusters);
return data;
} public static InstanceQuery getQuery() {
InstanceQuery query = null;
try {
query = new InstanceQuery();
} catch (Exception e) {
e.printStackTrace();
}
query.setDatabaseURL("jdbc:oracle:thin:@192.168.2.67:1521:orcl");
query.setUsername("...");
query.setPassword("...");
return query;
}
三、代码
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Random;import weka.core.Instance;
import weka.core.Instances;
import weka.core.Utils;
import weka.experiment.InstanceQuery; public class DisKmeans { private static int numClusters = 20;
private static int maxInteration = 600;
private static Instances clusterCentroids;
private static Instances[] kmeansResult; public static void main(String[] args) throws Exception {
Instances data = getData();
System.out.println("start");
System.out.println(data.size());
System.out.println(data.instance(1));
Instance instance = data.instance(1);
for (int i=0; i<instance.numAttributes(); i++) {
// System.out.println(instance.attribute(i).value(0));
System.out.println(instance.toString(i));
}
System.out.println("~~~~~~~~~" + instance.value(3)); getKMeansResult(data);
printClusterResult();
updateToDB();
} /**
* 获取k个中心点
* @param data
* @return
* @throws Exception
*/
public static Instances getCentroid(Instances data) throws Exception {
System.out.println("-------------聚类中心-----------");
if (data.numInstances() == 0) {// 判断输入的数据文件是否为空。
throw new Exception("输入数据为空值!请检查数据集文件");
}
Random random = new Random(10);
int insIndex = 0;
clusterCentroids = new Instances(data, numClusters);
for (int i=data.numInstances()-1; i>=0 ; i--) {
insIndex = random.nextInt(i);//保证i不会超过数组上线
clusterCentroids.add(data.instance(insIndex));
if (clusterCentroids.numInstances() == numClusters) {
break;
}
}
// System.out.println(clusterCentroids);
printInstances(clusterCentroids);
System.out.println("-----------聚类中心结束-------------");
return clusterCentroids;
} /**
* 根据初始中心点,对数据进行第一次聚类,结果为初始聚类结果
* @param data
* @param centroids
* @return
*/
public static Instances[] createCluster(Instances data, Instances centroids) {
Instances[] newData = new Instances[centroids.numInstances()];
for (int i=0; i<newData.length; i++) {
//初始化newData数组中的Instances实例。取data的header作为实例头,初始容量为0;
newData[i] = new Instances(data, 0);
newData[i].add(centroids.instance(i));
}
for (int i=0; i<data.numInstances(); i++) {
double[] tempDis = new double[centroids.numInstances()];
for (int j=0; j<centroids.numInstances(); j++) {
if (!equalsInstance(data.instance(i), centroids.instance(j))) { // 重写Instance的equals方法。见EqualsInstance类
// 用欧式距离计算数据中其他实例和中心点实例的距离。
tempDis[j] = computeDistance(data.instance(i),centroids.instance(j));
}
}//end for(j)
int smallIndex = Utils.minIndex(tempDis);
newData[smallIndex].add(data.instance(i));
}//end for(i)
return newData;
} /**
* 得到cluster的中心点
* @param data
* @return
*/
public static Instance meanCentroid(Instances data) {
double sumValue = 0.0;
double avgValue = 0.0;
if (data.numInstances() <= 0) return null;
if (data.numInstances() == 1) return data.firstInstance();
Instance meanIns = data.firstInstance();
for (int i=3; i<data.numAttributes(); i++) {
for (int j=1; j<data.numInstances(); j++) {
sumValue += data.instance(j).value(i);
}
avgValue = sumValue / data.numInstances();
meanIns.setValue(data.attribute(i), avgValue);
sumValue = 0.0;
avgValue = 0.0;
}
return meanIns;
} private static Instances updateCentroids(Instances centroids, Instance instance, int index) {
centroids.add(instance);
int temp = centroids.numInstances() - 1;
centroids.swap(index, temp);
centroids.delete(temp);
return centroids;
} public static Instances[] getKMeansResult(Instances data) throws Exception {
System.out.println("聚类开始");
clusterCentroids = getCentroid(data);//k个中心点
kmeansResult = createCluster(data, clusterCentroids);//第一次聚类 for (int i=0; i<maxInteration; i++) {
Instances newCentroids = new Instances(clusterCentroids);
for (int j=0; j<kmeansResult.length; j++) {
Instances cluster = kmeansResult[j];
Instance tmpIns = meanCentroid(cluster);
newCentroids = updateCentroids(newCentroids, tmpIns, j);
}
System.out.println("迭代......" + (i + 1));
if (equalsInstance(newCentroids, clusterCentroids)) {
System.out.println("中心点集合不再变化!迭代次数" + (i + 1));
break;
}
clusterCentroids = newCentroids;
kmeansResult = createCluster(data, clusterCentroids);//根据中心点,重新聚类 if (i==maxInteration-2 || i==maxInteration-1) {
printInstances(clusterCentroids);
}
}
System.out.println("~~~~~~~~~聚类结束~~~~~~~~~");
printInstances(clusterCentroids);
return kmeansResult;
} public static void printClusterResult() throws IOException {
// System.out.println("聚类结果:");
int i=0;
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("result.txt")));
for (Instances ins : kmeansResult) {
// System.out.println("cluster " + i++ + ":");
bw.append("cluster " + i++ + ":\n");
@SuppressWarnings("rawtypes")
Enumeration en = ins.enumerateInstances();
while (en.hasMoreElements()) {
// System.out.println(en.nextElement());
bw.append(en.nextElement().toString());
bw.append("\n");
}
// System.out.println();
bw.append("\n");
}
bw.flush();
bw.close();
} public static Instances getData() throws Exception {
InstanceQuery query = getQuery();
String sql = "...................................................................";
Instances data = query.retrieveInstances(sql);
if (data.numInstances() <= 0)
throw new Exception("data size is 0;");
clusterCentroids = new Instances(data, numClusters);
return data;
} public static InstanceQuery getQuery() {
InstanceQuery query = null;
try {
query = new InstanceQuery();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
query.setDatabaseURL("jdbc:oracle:thin:@192.168.2.67:1521:orcl");
query.setUsername("...");
query.setPassword("...");
return query;
} private static double computeDistance(Instance in1, Instance in2) {
double dis = 0.0;
// if ( in1.toString(0).equals(in2.toString(0)) ) {
// dis += 1;
// }
// if ( in1.toString(2).equals(in2.toString(2)) ) {
// dis += 5;
// }
for (int k=3; k<in1.numAttributes(); k++) {
double dicrim = in1.value(k) - in2.value(k);
dis += dicrim*dicrim;
}
return dis;
} private static boolean equalsInstance(Instance in1, Instance in2) {
return in1.equals(in2);
} private static boolean equalsInstance(Instances ins1, Instances ins2) {
boolean flag = true;
if (ins1.numInstances() != ins2.numInstances()) return false;
for (int i=0; i<ins1.numInstances(); i++) {
if (computeDistance(ins1.instance(i), ins2.instance(i)) >= 0.0001) {
flag = false;
break;
}
}
return flag;
} public static void printInstances(Instances instances) {
for (int i=0; i<instances.numInstances(); i++) {
System.out.println(instances.instance(i));
}
}
}
四、其他
1、离散变量:数据中有个有用的离散变量,不方便直接放到kmeans算法中。但一定要用,也是可以的。
2、DatabaseUtils.props文件,在jar包中不方便直接修改,而我用解压工具修改在压缩回去,虽然可行,总觉得不太好。不知道有什么更好的方法?
kmeans聚类源代码的更多相关文章
- Kmeans聚类算法原理与实现
Kmeans聚类算法 1 Kmeans聚类算法的基本原理 K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚类,对 ...
- 机器学习算法-K-means聚类
引文: k均值算法是一种聚类算法.所谓聚类.他是一种无监督学习,将类似的对象归到同一个蔟中.蔟内的对象越类似,聚类的效果越好. 聚类和分类最大的不同在于.分类的目标事先已知.而聚类则不一样. 由于其产 ...
- 4.无监督学习--K-means聚类
K-means方法及其应用 1.K-means聚类算法简介: k-means算法以k为参数,把n个对象分成k个簇,使簇内具有较高的相似度,而簇间的相似度较低.主要处理过程包括: 1.随机选择k个点作为 ...
- K-Means 聚类算法
K-Means 概念定义: K-Means 是一种基于距离的排他的聚类划分方法. 上面的 K-Means 描述中包含了几个概念: 聚类(Clustering):K-Means 是一种聚类分析(Clus ...
- 用scikit-learn学习K-Means聚类
在K-Means聚类算法原理中,我们对K-Means的原理做了总结,本文我们就来讨论用scikit-learn来学习K-Means聚类.重点讲述如何选择合适的k值. 1. K-Means类概述 在sc ...
- K-Means聚类算法原理
K-Means算法是无监督的聚类算法,它实现起来比较简单,聚类效果也不错,因此应用很广泛.K-Means算法有大量的变体,本文就从最传统的K-Means算法讲起,在其基础上讲述K-Means的优化变体 ...
- K-means聚类算法
聚类分析(英语:Cluster analysis,亦称为群集分析) K-means也是聚类算法中最简单的一种了,但是里面包含的思想却是不一般.最早我使用并实现这个算法是在学习韩爷爷那本数据挖掘的书中, ...
- k-means聚类算法python实现
K-means聚类算法 算法优缺点: 优点:容易实现缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢使用数据类型:数值型数据 算法思想 k-means算法实际上就是通过计算不同样本间的距离来判断他 ...
- K-Means 聚类算法原理分析与代码实现
前言 在前面的文章中,涉及到的机器学习算法均为监督学习算法. 所谓监督学习,就是有训练过程的学习.再确切点,就是有 "分类标签集" 的学习. 现在开始,将进入到非监督学习领域.从经 ...
随机推荐
- springbatch---->springbatch的使用(六)
前面的例子step都是线性的流程,这里我们提供一个非线性的流程,也就是根据不同的状态做不同的流程step处理.万一有天悔恨变得太现实太世故太麻木,说不定能从回忆中重拾随兴飞翔. step非线性的流程 ...
- shell截取字符串的一些简单方法
一.使用${} 1.${var##*/}该命令的作用是去掉变量var从左边算起的最后一个'/'字符及其左边的内容,返回从左边算起的最后一个'/'(不含该字符)的右边的内容.使用例子及结果如下:
- 【linux系列】yum安装报错 no mirrors to try
执行以下命令去重新生成缓存 yum clean all yum makecache 更换源重新下载repo文件 重新生成缓存
- 【Redis使用系列】使用Redis做防止重复提交
前言 在平时的开发中我们都需要处理重复提交的问题,避免业务出错或者产生脏数据,虽然可以通过前端控制但这并不是可以完全避免,最好的方式还是前后端均进行控制,这样的话就可以更有效,尽可能全面的去减少错误的 ...
- JS笔记 - JQ事件委托( 适用于给动态生成的脚本元素添加事件)
最近一段时间打了一个大仗,现在总算消停点,才有时间来做个总结吧算是: 移动端遇到一个项目,是一个列表的侧滑栏,在我这里用jq写的交互事件.自测各方面都挺好的,美滋滋的给了研发.研发也美滋滋的开始开发. ...
- Android.mk(3) 宏
https://www.jianshu.com/p/7c20b299ee63 传统上我们一直称这种东西为makefile中的变量,其实本质上就是一个宏,只是做的是字符串替换.我们何如就把它叫做宏呢. ...
- Android studio 插件安装
安装插件步骤 一 CodeGlance 最大的用途:可用于快速定位代码.显示在右侧 二 Android Studio Prettify 可以将代码中的字符串写在string.xml文件中 选中字符串鼠 ...
- linux下模拟CPU占用100%小程序
在做一个测试时,需要模拟服务器CPU占用满的情况,在查阅相关资料后,发现网上程序不太好用, 原文在这:http://www.2cto.com/os/201304/202068.html 优化后如下: ...
- 一个简单web系统的接口性能分析及调优过程
在测试一个简单系统接口性能压力时,压到一定数量,程序总是崩溃,查看相关机器相关数据时,CPU.内存.IO占用均不高,问题自然出现在其它地方先介绍下系统部件架构 Resin版本为:[root@local ...
- [分布式系统学习]阅读笔记 Distributed systems for fun and profit 之三 时间和顺序
这是阅读 http://book.mixu.net/distsys/time.html 的笔记,是该系列的第三章. 为什么时间和顺序很重要呢?为什么我们关系事件A发生在事件B之前? 因为分布式系统要解 ...