# Weka算法Clusterers-Xmeans源码分析（二）




 protected Instances splitCenter(Random random,
Instance center,
double variance,
Instances model) throws Exception {
m_NumSplits++;
AlgVector r = null;
Instances children = new Instances(model, 2);

if (m_DebugVectorsFile.exists() && m_DebugVectorsFile.isFile()) {
Instance nextVector = getNextDebugVectorsInstance(model);
PFD(D_RANDOMVECTOR, "Random Vector from File " + nextVector);
r = new AlgVector(nextVector);
}
else {
//这个model是表头，r是生成一个随机向量，每一维都是0到1之间
r = new AlgVector(model, random);
}
r.changeLength(Math.pow(variance, 0.5));//改变向量的长度为sqrt(variance)这个variance就是聚类点到聚类中心的平均偏差
PFD(D_RANDOMVECTOR, "random vector *variance "+ r);

// 首先生成两个聚类中心的向量
AlgVector c = new AlgVector(center);
AlgVector c2 = (AlgVector) c.clone();
Instance newCenter = c.getAsInstance(model, random);
PFD(D_FOLLOWSPLIT, "first child "+ newCenter);

// c2-r
c2 = c2.substract(r);
newCenter = c2.getAsInstance(model, random);
PFD(D_FOLLOWSPLIT, "second child "+ newCenter);

return children;
}

protected Instances newCentersAfterSplit(double[] pbic,
double[] cbic,
double cutoffFactor,
Instances splitCenters) {

//
boolean splitPerCutoff = false;
boolean takeSomeAway = false;
boolean[] splitWon = initBoolArray(m_ClusterCenters.numInstances());//这个数组存放每个聚类中心是否分裂的决定
int numToSplit = 0;
Instances newCenters = null;

for (int i = 0; i < cbic.length; i++) {
if (cbic[i] > pbic[i]) {
// 如果child的BIC比较大，就分裂，为什么是BIC越大越好而不是越小越好？Weka的BIC公式貌似没取负。
splitWon[i] = true; numToSplit++;
PFD(D_FOLLOWSPLIT, "Center " + i + " decide for children");
}
else {
// 默认是false，不用重新赋值。
PFD(D_FOLLOWSPLIT, "Center " + i + " decide for parent");
}
}

if ((numToSplit == 0) && (cutoffFactor > 0)) {
splitPerCutoff = true;

// 如果没有节点需要分裂，则使用cutoffFactor来决定要分裂的数量，这么做的原因是为了防止陷入局部最优点。
numToSplit = (int)
((double) m_ClusterCenters.numInstances() * m_CutOffFactor);
}

// 把pbic和cbic进行相减，并排序，以便找出差最大的，优先分裂。
double[] diff = new double [m_NumClusters];
for (int j = 0; j < diff.length; j++) {
diff[j] = pbic[j] - cbic[j];
}
int[] sortOrder = Utils.sort(diff);

//检查一下最多的可分裂数量
int possibleToSplit = m_MaxNumClusters - m_NumClusters;

if (possibleToSplit > numToSplit) {
// 如果可分裂数量多于numToSplit，就按照numToSplit去分裂
possibleToSplit = numToSplit;
}
else
takeSomeAway = true;

// 如果有splitPerCuteoff标，说明使用了cutoffFactor来决定分裂多少，这时候splitWon里面肯定都是false，需要设置一定数量的为true
if (splitPerCutoff) {
for (int j = 0; (j < possibleToSplit) && (cbic[sortOrder[j]] > 0.0);
j++) {
splitWon[sortOrder[j]] = true;
}
m_NumSplitsStillDone += possibleToSplit;
}
else {
// take some splits away if max number of clusters would be exceeded
if (takeSomeAway) {
int count = 0;
int j = 0;//如果有这个标，说明能分裂的数量小于了splitWon中的数量，需要将一定数量得true设置为false
for (;j < splitWon.length && count < possibleToSplit; j++){
if (splitWon[sortOrder[j]] == true) count++;
}

while (j < splitWon.length) {
splitWon[sortOrder[j]] = false;
j++;
}
}
}

// 进行分裂操作，即若splitWon==true就分裂，否则保持原样
if (possibleToSplit > 0)
newCenters = newCentersAfterSplit(splitWon, splitCenters);
else
newCenters = m_ClusterCenters;
return newCenters;
}

1、随机选取聚类中心

2、对于每个实例，分配到离其最近的聚类中心

3、重新计算新的聚类中心

4、尝试对新的聚类中心进行分裂

5、回到2，若连续两个循环结果相同，则结束

1、如何计算各用例之间的“距离”

2、所谓的“迭代退出条件”是什么。

3、如何确定聚类中心

4、在实现过程中有没有一些用来提高效率的trick