K平均法によるクラスタリング
K平均法によるクラスタリングの可視化
参考文献:集合知プログラミング(http://www.oreilly.co.jp/books/9784873113647/)
/**
* Copyright termat ( http://wonderfl.net/user/termat )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/uKm0
*/
/*
K平均法によるクラスタリングの可視化
参考文献:集合知プログラミング(http://www.oreilly.co.jp/books/9784873113647/)
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
[SWF(framerate = "10", width = "500",height="500",backgroundColor="0x000000")]
public class Practice31 extends Sprite{
private var cont:Controller;
private const numOfSample:int = 160;
private const numOfGroup:int = 10;
public function Practice31() {
cont = new Controller(this, numOfGroup);
for (var i:int = 0; i < numOfSample; i++) {
var m:Sample = new Sample();
m.x = 500 * Math.random();
m.y = 500 * Math.random();
addChild(m);
cont.sample.push(m);
}
addEventListener(Event.ENTER_FRAME,update);
}
private function update(e:Event):void {
if (!cont.completed) {
cont.update(e);
}
}
}
}
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import caurina.transitions.Tweener;
class Controller {
private var kave:Vector.<Cog>;
public var sample:Vector.<Sample>;
private var splite:Sprite;
private var index:int;
private var num:int;
public var completed:Boolean = false;
public function Controller(s:Sprite, n:int):void {
splite = s;
kave = new Vector.<Cog>();
sample = new Vector.<Sample>();
for (var i:int = 0; i < n; i++) {
var cr:Number = (i / n) * 360.0;
var k:Cog = new Cog(getColor(cr));
k.x = 500 * Math.random();
k.y = 500 * Math.random();
kave.push(k);
splite.addChild(k);
}
index = 0;
num = 0;
}
public function update(e:Event):void {
if (index < sample.length) {
num +=checkGroup(index++);
}else {
splite.graphics.clear();
if (num == 0) completed = true;
if (completed)return;
for (var i:int = 0; i < kave.length; i++) {
var p:Point = kave[i].getGrav();
Tweener.addTween( kave[i], { x:p.x, y:p.y, time:30, useFrames:true, transition:"easeOutExpo"});
kave[i].clear();
}
index = 0;
num = 0;
}
}
private function checkGroup(i:int):int {
splite.graphics.clear();
var ret:int = sample[i].findGroup(kave);
splite.graphics.lineStyle(1.0, 0xffff00);
splite.graphics.moveTo(sample[i].group.x, sample[i].group.y);
splite.graphics.lineTo(sample[i].x, sample[i].y);
return ret;
}
private function getColor(i:int):uint {
var h:Number = i / 60;
var ii:Number = Math.floor(h);
var ff:Number = h - ii;
var p1:Number = 0.0;
var p2:Number = 1.0 - ff;
var p3:Number = 1.0 - (1.0 - ff);
var rv:Number;
var gv:Number;
var bv:Number;
switch(ii) {
case 0:
rv = 1.0; gv = p3; bv = p1;
break;
case 1:
rv = p2; gv = 1.0; bv = p1;
break;
case 2:
rv = p1; gv = 1.0; bv = p3;
break;
case 3:
rv = p1; gv = p2; bv = 1.0;
break;
case 4:
rv = p3; gv = p1; bv = 1.0;
break;
default:
rv = 1.0; gv = p1; bv = p2;
}
var rr:int = Math.max(0, Math.min(255, rv * 255));
var gg:int = Math.max(0, Math.min(255, gv * 255));
var bb:int = Math.max(0, Math.min(255, bv * 255));
var color:uint = (rr << 16) + (gg << 8) + bb;
return color;
}
}
class Cog extends MovieClip{
private var list:Vector.<Sample>;
public var color:uint = 0x666666;
public function Cog(c:uint):void {
list = new Vector.<Sample>();
color = c;
graphics.beginFill(color);
graphics.drawCircle(0,0,12);
graphics.endFill();
}
public function addSample(m:Sample):void {
list.push(m);
}
public function removeSample(m:Sample):void {
for (var i:int = 0; i < list.length; i++) {
var obj:Sample = list.shift();
if (m == obj) return;
list.push(obj);
}
}
public function clear():void {
while (list.length > 0) list.pop();
}
public function distance(s:Sample):Number {
var xx:Number = x - s.x;
var yy:Number = y - s.y;
return Math.sqrt(xx * xx + yy * yy);
}
public function getGrav():Point {
if (list.length == 0) {
return new Point(x, y);
}else {
var avex:Number = 0;
var avey:Number = 0;
for each(var m:Sample in list) {
avex += m.x;
avey += m.y;
}
return new Point(avex / list.length, avey / list.length);
}
}
}
class Sample extends MovieClip {
public var group:Cog = null;
private var size:Number = 20 * Math.random();
public function Sample():void {
draw(0xffffff);
}
public function findGroup(list:Vector.<Cog>):int {
var tmp:Cog = null;
var len:Number = 99999999;
for each(var k:Cog in list) {
var l:Number = k.distance(this);
if (len > l) {
tmp = k;
len = l;
}
}
if (group == tmp) {
group.addSample(this);
return 0;
}else {
if (group != null) group.removeSample(this);
group = tmp;
group.addSample(this);
draw(group.color);
return 1;
}
}
private function draw(c:uint):void {
graphics.clear();
graphics.beginFill(c,0.4);
graphics.drawCircle(0,0,size);
graphics.endFill();
}
}