무작위
로 K개의 중심점을 설정하고, 데이터 포인트들을 가장 가까운 중심점에 할당한 뒤, 새로운 중심점을 계산하여 클러스터를 업데이트하는 방식이다.export interface Point {
x?: number;
y?: number;
}
export class KMeans {
private k: number;
private data: Point[];
private centroids: Point[];
constructor(k: number, data: Point[]) {
this.k = k;
this.data = data;
this.centroids = this.initializeCentroids();
}
private initializeCentroids(): Point[] {
const centroids: Point[] = [];
const dataCopy = this.data.slice();
for (let i = 0; i < this.k; i++) {
const randomIndex = Math.floor(Math.random() * dataCopy.length);
centroids.push(dataCopy.splice(randomIndex, 1)[0]);
}
return centroids;
}
private euclideanDistance(a: Point={x:0,y:0}, b: Point={x:0,y:0}): number {
return Math.sqrt(((a.x || 0) - (b.x || 0)) ** 2 + ((a.y || 0) - (b.y || 0)) ** 2);
}
private updateCentroids(clusteredData: Point[][]): void {
this.centroids = clusteredData.map((cluster) => {
const clusterSize = cluster.length;
const sumX = cluster.reduce((sum, point) => sum + (point.x || 0), 0);
const sumY = cluster.reduce((sum, point) => sum + (point.y || 0), 0);
return { x: sumX / clusterSize, y: sumY / clusterSize };
});
}
private assignDataToCentroids(): Point[][] {
const clusteredData: Point[][] = new Array(this.k).fill(null).map(() => []);
this.data.forEach((point) => {
let minDistance = Number.MAX_VALUE;
let closestCentroidIndex = -1;
this.centroids.forEach((centroid, index) => {
const distance = this.euclideanDistance(point, centroid);
if (distance < minDistance) {
minDistance = distance;
closestCentroidIndex = index;
}
});
clusteredData[closestCentroidIndex].push(point);
});
return clusteredData;
}
public run(maxIterations: number = 100): void {
for (let i = 0; i < maxIterations; i++) {
const clusteredData = this.assignDataToCentroids();
this.updateCentroids(clusteredData);
}
}
public getClusters(): Point[][] {
return this.assignDataToCentroids();
}
public getCentroid(): Point[]{
return this.centroids;
}
}
// 클러스터링 만드는 함수
const clusterData = kMeans.getClusters();
const clusterCircle = kMeans.getCentroid();
if(vw3dViewer.value.camera._positionCartographic.height > 10000){
clusterCircle.forEach((data, index) => {
vw3dViewer.value.entities.add({
position: Cesium.Cartesian3.fromDegrees(data.x, data.y, 4000.0),
label: {
text: clusterData[index].length.toString(),
font: '24px Helvetica',
fillColor: ws3d.value.common.Color.GOLD,
outlineColor: ws3d.value.common.Color.GOLD,
outlineWidth: 2,
},
name: "Green circle at height with outline",
ellipse: {
semiMinorAxis: 30000.0/kCount.value^50,
semiMajorAxis: 30000.0/kCount.value^50,
height: 4000.0,
material: ws3d.value.common.Color.ROYALBLUE,
outline: true,
},
});
})
}
initializeCentroids 메서드:
assignDataToCentroids 메서드:
즉, initializeCentroids 메서드는 초기 중심점을 설정하고 assignDataToCentroids 메서드는 데이터를 클러스터에 할당하는 역할을 수행한다.
이후에는 updateCentroids 메서드를 통해 클러스터링 결과에 따라 중심점을 업데이트하며 알고리즘이 반복적으로 실행된다.