Kmeans聚类过程的动态可视化

最近在做一个推荐系统的时候,我们采用的方法是基于SVD的K-means聚类协同过滤算法,其中在实现Kmeans聚类算法的时候参考了一篇文章,里面给出了算法代码,并且很有新意的把最终的聚类结果以散点图的形式展示了一下。于是昨天我突发奇想,可不可以把整个Kmeans聚类过程可视化出来,这样还能更好的帮助我们理解Kmeans具体的过程细节,听起来很有意思,有了想法想尽快实现它,在午饭的时候还一直思考着该如何下手。由于很久没用过d3了,有了想法还得一边上网查d3的语法,看来还得好好学一下了。昨天在查阅了d3比例尺坐标轴等资料后,终于在晚上实现了动态可视化,真是太激动了!

Kmeans算法介绍

k-means算法是一种很常见的聚类算法,它的基本思想是:通过迭代寻找k个聚类的一种划分方案,使得用这k个聚类的均值来代表相应各类样本时所得的总体误差最小。

k-means算法的基础是最小误差平方和准则。其代价函数是:
Kmeans代价函数

式中,μc(i)表示第i个聚类的均值。我们希望代价函数最小,直观的来说,各类内的样本越相似,其与该类均值间的误差平方越小,对所有类所得到的误差平方求和,即可验证分为k类时,各聚类是否是最优的。

上式的代价函数无法用解析的方法最小化,只能有迭代的方法。k-means算法是将样本聚类成 k个簇(cluster),其中k是用户给定的,其求解过程非常直观简单,具体算法描述如下:

  1. 随机选取 k个聚类质心点

  2. 重复下面过程直到收敛 {

    对于每一个样例 i,计算其应该属于的类:
    计算样例所属类

    对于每一个类 j,重新计算该类的质心:
    计算质心
    }

下面用文字描述一下Kmeans的伪代码:

创建k个点作为初始的质心点(随机选择)

当任意一个点的簇分配结果发生改变时

      对数据集中的每一个数据点

             对每一个质心

                    计算质心与数据点的距离

             将数据点分配到距离最近的簇

      对每一个簇,计算簇中所有点的均值,并将均值作为质心

下面上Kmeans聚类用js实现的代码:

在Kmeans聚类中,我们一般使用欧氏距离作为质心与数据点的误差度量,因此我们在定义一个距离函数:

function euclDistance(vector1, vector2) {
   
    var dx = vector1.x - vector2.x;
    var dy = vector1.y - vector2.y;
    return Math.sqrt(dx*dx + dy*dy);
}

按照第一步,我们首先要随机选取k个质心,k就是我们要聚类的类的个数,data是数据点的数组,会在下一节中提到。下面看代码:

function initCentroids(data, k) {
   
	var centroids = new Array();
	var indices = [];
	var i = 0;
	while(i < k) {
   
	    var index = getRandomNum(0, length);
	    if(contains(indices, index)) {
   
	        continue;
	    } else {
   
	        indices.push(index);
	        i++;
	        var node = {
   };
	        node.x = data[index].x;
	        node.y = data[index].y;
	        node.index = index;
	        centroids.push(node);
	    }
	}
	console.log(centroids);
	return centroids;
}

这里用到的getRandomNum函数是用来获取0~length-1之间的随机数的,代码见下:

function getRandomNum(min, max) {
   
	var range = max - min;
    var rand = Math.random();
    return(min + Math.floor(rand * range));
}

并且为了保证在随机选取质心的时候不会重复选择,我们需要确保每次获取的随机数并没使用过,于是我们用一个数据保存已经使用了的随机数,然后每次检查一下数组是否包含了(contains)得到的新随机数:

function contains(arr, obj) {
   
	var i = arr.length;
	while (i--) {
   
	    if (arr[i] === obj) {
   
	        return true;
	    }
	}
	return false;
}

第二步,重复计算知道收敛,即所有数据点所属类别不再变化。代码(代码中出现的画图函数将会在下一节中描述):

function kmeans(data, k) {
   

	var centroids = initCentroids
  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值