Weka开发[9]—KMeans源码介绍

以前介绍的都是分类的内容,这一次介绍聚类,以最简单的SimpleKMeans源码为例。

分类中训练一个分类器是用buildClassifier(),在聚类中学习一个Clusterer是用buildCluster()。分类中分类一个样本是用classifyInstance,而在聚类中是用clusterInstance。那我怎么知道这些的呢?(或者说:你怎么知道我是不是在骗你呢?)以ID3为例,你可以看出它继承自Classifier类,进入Classifier类,它有三个比较重要的函数,buildClassifer, classifyInstance, distributionForInstance(这个应该讲过了)。那么如果你在看SimpleKMeans那么可以看它继承自RandomizableCluster,而RandomizableCluster又继承自AbstactCluter,进入AbstactCluster,它也有三个比较重要的函数,buildCluster, clusterInstance, distributionForInstance。关联规则的自己找。但所有的这些最初我是如何知道的呢?同学告诉我的,我也问过他最初如何知道的呢?他神秘地告诉我:源代码。

for (int j = initInstances.numInstances() - 1; j >= 0; j--) {
    instIndex = RandomO.nextInt(j + 1);
    hk = new DecisionTableHashKey(initInstances.instance(instIndex),
           initInstances.numAttributes(), true);
    if (!initC.containsKey(hk)) {
       m_ClusterCentroids.add(initInstances.instance(instIndex));
       initC.put(hk, null);
    }
    initInstances.swap(j, instIndex);
 
    if (m_ClusterCentroids.numInstances() == m_NumClusters) {
       break;
    }
}

以上是随机产生centroid的代码,也没什么特别之处,用RandomO产生一个index,如果这个index所指向的样本不是一个中心点了(用Hash表记录),把这个样本加入m_ClusterCentroids中,m_ClusterCentroids中保存的是所有中心点。最后一个if判断如果产生了用户最初设置的cluster的个数,break。

   for (i = 0; i < instances.numInstances(); i++) {
       Instance toCluster = instances.instance(i);
       int newC = clusterProcessedInstance(toCluster, true);
       if (newC != clusterAssignments[i]) {
           converged = false;
       }
       clusterAssignments[i] = newC;
    }

对每一个样本,用clusterProcessedInstance函数判断它属于哪个cluster,它属于哪个cluster当然就是根据它离哪个centroid近来决定了,再判断新的cluster和以前的cluster是否一样,如果不一样,那么就还没有converge,clusterAssignments[i]是第i个样本属于某个cluster。

// update centroids
m_ClusterCentroids = new Instances(instances, m_NumClusters);
for (i = 0; i < m_NumClusters; i++) {
    tempI[i] = new Instances(instances, 0);
}
for (i = 0; i < instances.numInstances(); i++) {
    tempI[clusterAssignments[i]].add(instances.instance(i));
}
for (i = 0; i < m_NumClusters; i++) {
    if (tempI[i].numInstances() == 0) {
    // empty cluster
    emptyClusterCount++;
    } else {
       moveCentroid(i, tempI[i], true);
    }
}

以上代码是更新centroid,TempI[i]中保存的是所以当前属于第i个cluster的所有样本。最后一个for循环,如果tempI[i]中没有样本,那么记录有一个空cluster,如果tempI[i]中有样本,moveCentroid函数移动中心点。moveCentroid这个函数稍稍介绍一下,先看代码前的三句注释,我这里就不翻译了:

// in case of Euclidian distance the centroid is the mean point
// in case of Manhattan distance the centroid is the median point
// in both cases, if the attribute is nominal, the centroid is the mode
if (m_DistanceFunction instanceof EuclideanDistance
                  || members.attribute(j).isNominal()) {
    vals[j] = members.meanOrMode(j);
} else if (m_DistanceFunction instanceof ManhattanDistance) {
    // singleton special case
    if (members.numInstances() == 1) {
       vals[j] = members.instance(0).value(j);
    } else {
       sortedMembers.kthSmallestValue(j, middle + 1);
       vals[j] = sortedMembers.instance(middle).value(j);
       if (dataIsEven) {
           sortedMembers.kthSmallestValue(j, middle + 2);
    vals[j] = (vals[j] + sortedMembers.instance(middle + 
1).value(j)) / 2;
       }
    }
}

这里有一点我不太明白的是:为什么代码不用if和else把奇数,偶数分开,而是在偶数样本时计算两次,这种代码实在让我有点无法接受。有点需要解释的是为什么偶数的是时候用的是middle+2,这是因为这个coder在求middle的时候用的是(members.numInstances() - 1) / 2;这样如果是偶数实际求出来的middle就小1,另一点是因为数数是从0数起(讲这个有点污辱人了),所以是+2。这也是我吐血的一点,不就多写两行代码吗?何必把代码写的这么古怪。

对于每个属性,对于不同的距离公式,对于离散/连续属性,选择不同确定中心的方式。

判断聚类是否结束,第一种是如果每一个样本(也就是第二段代码)都在上一次产生的cluster中,也就是converged,另一种是用户设计的一个m_MaxIterations,如果达到最大迭代次数,也结束。

再看一下clusterInstance函数,请注意,它最后调用的clusterProcessedInstance, 刚才提了一下这个函数,这里把核心代码列出来:

for (int i = 0; i < m_NumClusters; i++) {
    double dist = m_DistanceFunction.distance(instance,
       m_ClusterCentroids.instance(i));
    if (dist < minDist) {
       minDist = dist;
       bestCluster = i;
    }
}

讲这种代码,实在没什么意思,就是比较m_NumClusters个中心点,看instance与哪一个中心点近,作为bestCluster返回。

时间: 2024-11-15 19:11:02

Weka开发[9]—KMeans源码介绍的相关文章

Weka开发[14]-AdaBoost源代码介绍

这一次讲的是Ensemble的东西,一位读者希望我讲一下Adaboost的内容,这种Ensemble看起来的确比较吓人,推荐一篇论文:Ensemble Based Systems in Decision Making. 在这里所有理论的东西我就不介绍了. 与以往一样,先看buildClassifier函数(我在函数中将不重要的代码全部去掉): super.buildClassifier(data); if ((!m_UseResampling)&& (m_Classifier instan

[转]MBProgressHUD 源码分析

源码来源: https://github.com/jdg/MBProgressHUD 版本:0.9.1 MBProgressHUD是一个显示HUD窗口的第三方类库,用于在执行一些后台任务时,在程序中显示一个表示进度的loading视图和两 个可选的文本提示的HUD窗口.我想最多是应用在加载网络数据的时候.其实苹果官方自己有一个带有此功能的类UIProgressHUD,只不过它是私有 的,现在不让用.至于实际的效果,可以看看github上工程给出的几张图例(貌似我这经常无法单独打开图片,所以就不在

Weka 开发[1]-Instances类

先google一下,把Weka软件下载下来,安装完成之后,在Weka的安装目录中有一个weka.jar的包. 把包添加到工程中后,就可以调用weka中的函数了. 再介绍一点weka的基本知识,在weka的目录下,有一个data的文件夹,里面存放的是一些数据集,以第一个数据集contact-lenses.arff为例,用EditPlus或是别的编辑器打开数据集,以%开头的表示的是一些注释,@relation表示这个数据集的名字,@attribute表示属性的属性,@data后就是数据集了,一般来说

Weka开发[4]-特征选择

特征选择,我对这一部分也不熟,大概讲一下,用AttributeSelection进行特征选择,它需要设置3个方面,第一:对属性评价的类(自己到Weka软件里看一下,英文Attribute Evaluator),第二:搜索的方式(自己到Weka软件里看一下,英文Search Method),第三:就是你要进行特征选择的数据集了.最后调用Filter的静态方法userFilter,感觉写的都是废话,一看代码就明白了.唯一值得一说的也就是别把AttributeSelection的包加错了,代码旁边有注

50个Android开发人员必备UI效果源码[转载]

50个Android开发人员必备UI效果源码[转载] http://blog.csdn.net/qq1059458376/article/details/8145497 Android 仿微信之主页面实现篇Android 仿微信之界面导航篇Android 高仿QQ 好友分组列表Android 高仿QQ 界面滑动效果Android 高仿QQ 登陆界面Android 对Path的旋转效果的拓展Android高仿360安全卫士布局源码Android SlidingDrawer 滑动抽屉效果Androi

karloop介绍--hello world大家好,今天为大家介绍一款非常轻量级的的web开发框架,karloop框架。使用python开发 首先我们下载karloop源码进行安装。 源码地址 下载成

大家好,今天为大家介绍一款非常轻量级的的web开发框架,karloop框架.使用python开发 首先我们下载karloop源码进行安装. 源码地址 下载成功后解压,进入解压后的路径,进入终端,运行命令:sudo python setup.py install 如果是window系统,则打开cmd,运行:python setup.py install 下载安装成功后,我们写一个hello.py 内容如下: # coding=utf-8 from karloop.KarlBaseApplicati

做应用开发的如何查看Android源码

当我们在eclipse中开发android程序的时候,往往需要看源代码(可能是出于好奇,可能是读源码习惯),那么如何查看Android源代码呢? 比如下面这种情况 图一 假设我们想参看Activity类的源代码,按着Ctrl键,左击它,现实的结果却看不到代码的,提示的信息便是"找不到Activity.class文件". 图二 此时点击下面的按钮,"Change Attached Source-",选择android源代码所在位置,便弹出图三的对话框. 图三 第一种是

使用SBT开发Akka第一个案例源码解析MapActor、ReduceActor、AggregateActor

学习了使用SBT开发Akka第一个案例源码解析MapActor.ReduceActor.AggregateActor,应用MapActor对单词计数,发信息给ReduceActor,对信息进行local级的汇总,然后交给AggregateActor. 案例如下: class MapActor(reduceActor: ActorRef) extend Actor{ val STOP_WORDS_LIST=List("a","is") deg receive: Rec

卡罗盾系统开发,卡罗盾系统源码

卡罗盾系统开发,卡罗盾系统源码,卡罗盾拆分制度是怎么样?卡罗盾CROD拆分制度系统开发,卡罗盾CROD挖矿系统开发,找伍生+薇(aac1287),卡罗盾CROD持币生息系统开发.卡罗盾CROD分红系统开发.卡罗盾CRODapp软件开发 特别提示:本公司是软件开发公司,非运营商,玩家勿扰,谢谢合作!!! 一.CROD卡罗盾区块链系统解析: 投资4200纯静态的利益,最慢100天回本,最快一个月,最少5倍纯利润,最多几十倍 享受大家资源 分享一人直接释放百分之五:分享3人,享受节点以下6层叠加收入的