MIF_E31221222/sigap-website/app/_utils/clustering.ts

121 lines
4.6 KiB
TypeScript

// // utils/clustering.ts
// import * as math from 'mathjs';
// interface ClusteringData {
// districtId: string;
// populationDensity: number;
// unemploymentRate: number;
// crimeCount: number;
// }
// export function normalizeData(data: ClusteringData[]): ClusteringData[] {
// // Ekstrak nilai untuk setiap dimensi
// const densities = data.map(item => item.populationDensity);
// const unemploymentRates = data.map(item => item.unemploymentRate);
// const crimeCounts = data.map(item => item.crimeCount);
// // Hitung min dan max untuk normalisasi
// const minDensity = Math.min(...densities);
// const maxDensity = Math.max(...densities);
// const minUnemployment = Math.min(...unemploymentRates);
// const maxUnemployment = Math.max(...unemploymentRates);
// const minCrimeCount = Math.min(...crimeCounts);
// const maxCrimeCount = Math.max(...crimeCounts);
// // Normalisasi data antara 0 dan 1
// return data.map(item => ({
// ...item,
// populationDensity: (item.populationDensity - minDensity) / (maxDensity - minDensity || 1),
// unemploymentRate: (item.unemploymentRate - minUnemployment) / (maxUnemployment - minUnemployment || 1),
// crimeCount: (item.crimeCount - minCrimeCount) / (maxCrimeCount - minCrimeCount || 1)
// }));
// }
// export function kMeansClustering(data: ClusteringData[], k = 3, maxIterations = 100): { clusters: number[], centroids: number[][] } {
// const normalizedData = normalizeData(data);
// // Mengubah data ke format yang sesuai untuk algoritma k-means
// const points = normalizedData.map(item => [
// item.populationDensity,
// item.unemploymentRate,
// item.crimeCount
// ]);
// // Inisialisasi centroid secara acak
// let centroids = Array(k).fill(0).map(() => {
// return [
// Math.random(),
// Math.random(),
// Math.random()
// ];
// });
// let clusters: number[] = [];
// let iterations = 0;
// let oldCentroids: number[][] = [];
// // Algoritma K-means
// while (iterations < maxIterations) {
// // Tetapkan setiap titik ke centroid terdekat
// clusters = points.map(point => {
// const distances = centroids.map(centroid =>
// Math.sqrt(
// Math.pow(point[0] - centroid[0], 2) +
// Math.pow(point[1] - centroid[1], 2) +
// Math.pow(point[2] - centroid[2], 2)
// )
// );
// return distances.indexOf(Math.min(...distances));
// });
// // Simpan centroid lama untuk mengetahui konvergensi
// oldCentroids = [...centroids];
// // Hitung centroid baru berdasarkan pengelompokan saat ini
// for (let i = 0; i < k; i++) {
// const clusterPoints = points.filter((_, index) => clusters[index] === i);
// if (clusterPoints.length > 0) {
// centroids[i] = [
// clusterPoints.reduce((sum, point) => sum + point[0], 0) / clusterPoints.length,
// clusterPoints.reduce((sum, point) => sum + point[1], 0) / clusterPoints.length,
// clusterPoints.reduce((sum, point) => sum + point[2], 0) / clusterPoints.length
// ];
// }
// }
// // Cek konvergensi
// const centroidChange = centroids.reduce((acc, curr, i) => {
// return acc + Math.sqrt(
// Math.pow(curr[0] - oldCentroids[i][0], 2) +
// Math.pow(curr[1] - oldCentroids[i][1], 2) +
// Math.pow(curr[2] - oldCentroids[i][2], 2)
// );
// }, 0);
// if (centroidChange < 0.001) {
// break;
// }
// iterations++;
// }
// // Urutkan cluster berdasarkan tingkat bahaya (tingkat kejahatan)
// // Semakin tinggi nilai pada centroid ketiga (crime count), semakin tinggi risikonya
// const orderedClusters = [...Array(k).keys()].sort((a, b) =>
// centroids[a][2] - centroids[b][2]
// );
// // Petakan cluster asli ke cluster terurut (low, medium, high)
// const mappedClusters = clusters.map(cluster =>
// orderedClusters.indexOf(cluster)
// );
// return { clusters: mappedClusters, centroids };
// }
// // Fungsi untuk mengubah hasil clustering ke format Prisma untuk disimpan
// export function mapClustersToCrimeRates(clusters: number[]): ('low' | 'medium' | 'high')[] {
// const rateMap = ['low', 'medium', 'high'] as const;
// return clusters.map(cluster => rateMap[cluster]);
// }