最近在玩一些数据分析相关的项目,接触到了一些数据分类的算法,这里介绍一些新学的kmeans聚类算法。kmeans和knn算法比较像都是利用过计算数据的距离进行分类,不同的是knn邻近算法需要给出已经经过分类的数据用来作为分类的依据,而kmeans算法则是只要给出要分几类,直接从需要分类的数据进行.
个人原创,版权所有,转载请注明原文出处,并保留原文链接:
https://www.embbnux.com/2015/10/15/use_kmeans_for_data_classification/
参考文章:Using python and k-means to find the dominant colors in images
一 kmeans聚类算法原理介绍
kmeans是数据挖掘算法里面一个比较基础的算法,输入一个k值,用来指定要区分多少类,还有一组需要被区分的数据data。
主要算法流程:
1. 在需要被分类的数据data随机选出k个数据,作为当前的k个类
2. 遍历所有需要聚类的数据,计算每一个需要聚类的数据与之前选的k个类的距离,把该数据关联到距离最近的类
3. 利用k个类所关联的数据重新算出一个类,替换与之关联的类,这个类称为新类,之前的类称为旧类。这个计算出的新的类称作引力中心
4. 计算k个类中旧类与新类的距离,这个称为类的移动距离,当k个类的移动距离小于某个设定的阈值,则完成算法,这k个类就是被聚类完成的k个类
二 使用js使用kmeans聚类算法用于获取图片主要颜色
kmeans的关键在于距离算法与引力中心算法,不同的应用场景主要的不同就是距离算法与引力中心算法,这里我以用js算出图片主要颜色为例:
首先要获取图片的数据,这里通过画到canvas再读出来实现图片每个像素颜色的获取:
function getImageData(image){ var ctx = document.getElementById('canvas').getContext('2d'); img = new Image(); img.src = image.src; ctx.drawImage(img, 0, 0, 100, 100); data = ctx.getImageData(0, 0, 200, 200).data; var points = [] for (var i = 0, l = data.length; i < l; i += 4) { var r = data[i]; var g = data[i+1]; var b = data[i+2]; points.push([r, g, b]); } return points }
计算点与点的距离,这里及颜色之间的差别
function euclidean(p1, p2) { var s = 0; for (var i = 0, l = p1.length; i < l; i++) { s += Math.pow(p1[i] - p2[i], 2) } return Math.sqrt(s); }
计算引力中心算法
function calculateCenter(points, n) { var vals = []; var plen = 0; for (var i = 0; i < n; i++) { vals.push(0); } for (var i = 0, l = points.length; i < l; i++) { plen++; for (var j = 0; j < n; j++) { vals[j] += points[i][j]; } } for (var i = 0; i < n; i++) { if (plen > 0){ vals[i] = vals[i] / plen; } } return vals; }
最终的Kmeans算法:
function kMeans(points, k, min_diff) { plen = points.length; clusters = []; seen = []; while (clusters.length < k) { idx = parseInt(Math.random() * plen); found = false; for (var i = 0; i < seen.length; i++ ) { if (idx === seen[i]) { found = true; break; } } if (!found) { seen.push(idx); clusters.push([points[idx], [points[idx]]]); } } while (true) { plists = []; for (var i = 0; i < k; i++) { plists.push([]); } for (var j = 0; j < plen; j++) { var p = points[j]; var smallest_distance = 10000000; var idx = 0; for (var i = 0; i < k; i++) { var distance = euclidean(p, clusters[i][0]); if (distance < smallest_distance) { smallest_distance = distance; idx = i; } } plists[idx].push(p); } var diff = 0; for (var i = 0; i < k; i++) { var old = clusters[i]; var list = plists[i]; var center = null; if (list.length > 0){ center = calculateCenter(plists[i], 3); }else{ center = calculateCenter(clusters, 3); } var new_cluster = [center, [center]]; var dist = euclidean(old[0], center); clusters[i] = new_cluster; diff = diff > dist ? diff : dist; } if (diff < min_diff) { break; } } return clusters; }
完成。
挽尊