相較於前一篇所實作的KNN「分類」演算法,本篇所要實作的則是K-means「分群」演算法(Unsupervised learning),兩者同樣都是使用Euclidean distance來決定和中心點的距離計算,只不過K-means還需要反覆不斷的修正K個中心點,直到K個點慢慢地趨於穩定才算完成,詳細的程式如下:
(本範例K值為3,所以一開始在畫面上點擊滑鼠左鍵會先依序分配3個分群的中心點,接著再不斷地點擊滑鼠左鍵就可以觀察到K點的變化,玩玩看吧>>kmeans)
Kmeans.as
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.utils.*;
public class Kmeans extends MovieClip
{
private var k:uint = 3;
private var count:uint = 0;
private var _r:uint = 0;
private var _g:uint = 0;
private var _b:uint = 0;
private var k_center:Array = new Array();
private var k_means:Array = new Array();
public function Kmeans()
{
stage.addEventListener(MouseEvent.MOUSE_UP,put);
init();
}
public function put(m:MouseEvent):void
{
if(count < k)
{
k_means[count] = new Array();
var c:Circle = null;
if(count == 0)
{
c = new Circle(0x0000FF);
}else if(count == 1)
{
c = new Circle(0x00FF00);
}else{
c = new Circle(0xFF0000);
}
c.x = stage.mouseX;
c.y = stage.mouseY;
addChild(c);
k_center[count] = c;
count++;
return;
}
for(var w = 0 ; w < 20 ; w++)
{
var cc2:Circle = this.getChildAt(w) as Circle;
var k_arr:Array = new Array();
var k_dict:Dictionary = new Dictionary(true);
for(var v = 0 ; v < k ;v++)
{
var k_c = k_center[v];
var dist2 = Point.distance(new Point(k_c.x,k_c.y),new Point(cc2.x,cc2.y));
k_dict[dist2] = k_c;
k_arr.push(dist2);
}
k_arr.sort(Array.NUMERIC);
var min = k_arr[0];
var color:uint = k_dict[min].getColor();
cc2.reDraw(color);
if(color == 0x0000FF)
{
k_means[0][_b] = new Point(cc2.x,cc2.y);
_b++;
}else if(color == 0x00FF00)
{
k_means[1][_g] = new Point(cc2.x,cc2.y);
_g++;
}else{
k_means[2][_r] = new Point(cc2.x,cc2.y);
_r++;
}
}
trace(_r+" "+_g+" "+_b);
var xx=0,yy=0;
for(var bb = 0 ; bb < _b ; bb++)
{
xx += k_means[0][bb].x;
yy += k_means[0][bb].y;
}
k_center[0].x = xx/_b;
k_center[0].y = yy/_b;
xx=0;yy=0;
for(var gg = 0 ; gg < _g ; gg++)
{
xx += k_means[1][gg].x;
yy += k_means[1][gg].y;
}
k_center[1].x = xx/_g;
k_center[1].y = yy/_g;
xx=0;yy=0;
for(var rr = 0 ; rr < _r ; rr++)
{
xx += k_means[2][rr].x;
yy += k_means[2][rr].y;
}
k_center[2].x = xx/_r;
k_center[2].y = yy/_r;
trace(k_center[0].x+" "+k_center[0].y);
}
public function init():void
{
for(var i = 0 ; i < 10 ; i++)
{
var c:Circle = new Circle(0x777777);
c.x = Math.random()*500;
c.y = Math.random()*500;
addChild(c);
}
for(i = 0 ; i < 10 ; i++)
{
var c2:Circle = new Circle(0x777777);
c2.x = Math.random()*500;
c2.y = Math.random()*500;
addChild(c2);
}
}
}
}
Circle.as
package
{
import flash.display.*;
public class Circle extends Sprite
{
private var color:uint = 0;
public function Circle(c:uint)
{
this.color = c;
this.graphics.lineStyle(5);
this.graphics.beginFill(this.color);
this.graphics.drawCircle(0,0,20);
this.graphics.endFill();
}
public function getColor():uint
{
return this.color;
}
public function reDraw(color:uint):void
{
this.graphics.clear();
this.graphics.lineStyle(5);
this.graphics.beginFill(color);
this.graphics.drawCircle(0,0,20);
this.graphics.endFill();
this.alpha = .5;
}
}
}


