From 33cff2186a5ca42f136ae23471741caea0b25b4e Mon Sep 17 00:00:00 2001
From: daffarahman11
Date: Wed, 28 May 2025 14:56:48 +0700
Subject: [PATCH] Revisi Bu Bitari PERTAMA rentang nilai k dan hapus CRUD
Kecamatan klaster
---
app/Http/Controllers/KmeansController.php | 5 +-
app/Http/Controllers/LandingController.php | 2 +-
app/Services/KMeansService.php | 179 ++++++++++--------
.../admin/dashboardListKecamatan.blade.php | 8 +-
.../admin/dashboardListKlaster.blade.php | 7 +-
.../views/components/layoutAdmin.blade.php | 20 +-
6 files changed, 129 insertions(+), 92 deletions(-)
diff --git a/app/Http/Controllers/KmeansController.php b/app/Http/Controllers/KmeansController.php
index 7d38616..4787454 100644
--- a/app/Http/Controllers/KmeansController.php
+++ b/app/Http/Controllers/KmeansController.php
@@ -13,7 +13,7 @@ class KmeansController extends Controller
public function KMeansCuras()
{
$data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')
- ->orderBy('kecamatan_id', 'asc')->get();
+ ->orderBy('jumlah_curas', 'asc')->get();
// Hitung min dan max untuk normalisasi
$min = $data->min('jumlah_curas');
@@ -123,12 +123,11 @@ public function KMeansCuras()
return redirect('/dashboard/TampilHitungCuras');
}
-
public function KMeansCuranmor()
{
// Ambil data awal
$data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')
- ->orderBy('kecamatan_id', 'asc')->get();
+ ->orderBy('jumlah_curanmor', 'asc')->get();
// Hitung min dan max untuk normalisasi Min-Max
$min = $data->min('jumlah_curanmor');
diff --git a/app/Http/Controllers/LandingController.php b/app/Http/Controllers/LandingController.php
index efd3b74..dbbdd0f 100644
--- a/app/Http/Controllers/LandingController.php
+++ b/app/Http/Controllers/LandingController.php
@@ -37,7 +37,7 @@ public function runKmeans()
$hasilKMeansCuranmor = $serviceKmeansCuranmor->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
- return redirect('/dashboard/curanmor');
+ return redirect('/dashboard');
}
diff --git a/app/Services/KMeansService.php b/app/Services/KMeansService.php
index ad6d18a..c0bf56f 100644
--- a/app/Services/KMeansService.php
+++ b/app/Services/KMeansService.php
@@ -16,21 +16,27 @@ public function hitungKMeansCuras()
$k = Klaster::count('id');
$maxIterasi = 100;
+ // Hitung min dan max untuk normalisasi
$minValue = $data->min('jumlah_curas');
$maxValue = $data->max('jumlah_curas');
+ // Normalisasi data dan simpan hasilnya ke dalam array baru
+ $normalizedData = $data->map(function ($item) use ($minValue, $maxValue) {
+ $normalized = ($item->jumlah_curas - $minValue) / ($maxValue - $minValue);
+ $item->normalized_curas = round($normalized, 2); // 2 angka di belakang koma
+ return $item;
+ });
+
+ // Inisialisasi centroid dengan nilai acak dari rentang normalisasi [0, 1]
$generated = collect();
while ($generated->count() < $k) {
- $random = mt_rand($minValue, $maxValue);
+ $random = round(mt_rand(0, 100) / 100, 2); // Random 0.00–1.00
if (!$generated->contains($random)) {
$generated->push($random);
}
}
- $centroids = $generated->map(function ($value) {
- return ['C' => $value];
- });
-
+ $centroids = $generated->map(fn($value) => ['C' => $value]);
$centroidAwal = $centroids->toArray();
$iterasi = [];
@@ -40,22 +46,27 @@ public function hitungKMeansCuras()
$clustered = [];
$currentAssignment = [];
- foreach ($data as $item) {
+ foreach ($normalizedData as $item) {
$jarak = [];
foreach ($centroids as $idx => $centroid) {
- $dist = abs($item->jumlah_curas - $centroid['C']);
- $jarak["C" . ($idx + 1)] = $dist;
+ $dist = abs($item->normalized_curas - $centroid['C']);
+ $jarak["C" . ($idx + 1)] = round($dist, 2); // Format 2 angka koma
}
- $iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
-
$minIndex = array_keys($jarak, min($jarak))[0];
$clusterNumber = (int) str_replace("C", "", $minIndex);
$clustered[$clusterNumber][] = $item;
$item->temp_klaster = $clusterNumber;
$currentAssignment[$item->id] = $clusterNumber;
+
+ // Tambahkan nilai normalisasi ke dalam iterasi
+ $iterasi[$i][] = array_merge(
+ ['kecamatan_id' => $item->kecamatan_id],
+ ['normal' => round($item->normalized_curas, 2)],
+ $jarak
+ );
}
if ($currentAssignment === $prevAssignment) {
@@ -64,9 +75,10 @@ public function hitungKMeansCuras()
$prevAssignment = $currentAssignment;
- // Update centroid berdasarkan rata-rata
+ // Update centroid
foreach ($clustered as $key => $group) {
- $avg = collect($group)->avg('jumlah_curas');
+ $avg = collect($group)->avg('normalized_curas');
+ $avg = round($avg, 2); // Format 2 angka koma
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
return $index === ($key - 1)
? ['C' => $avg]
@@ -77,16 +89,14 @@ public function hitungKMeansCuras()
// Final mapping centroid ke klaster_id
$finalCentroids = $centroids->map(function ($item, $index) {
- return ['index' => $index + 1, 'C' => $item['C']];
+ return ['index' => $index + 1, 'C' => round($item['C'], 2)];
})->sortBy('C')->values();
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
-
foreach ($finalCentroids as $i => $centroid) {
$centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
}
-
// Update ke database
foreach ($data as $item) {
Curas::where('id', $item->id)->update([
@@ -96,21 +106,24 @@ public function hitungKMeansCuras()
// Format centroid awal
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
- return ['C' . ($index + 1) => $item['C']];
+ return ['C' . ($index + 1) => round($item['C'], 2)];
});
// Format centroid akhir
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
- return ['C' . ($index + 1) => $item['C']];
+ return ['C' . ($index + 1) => round($item['C'], 2)];
});
+ // Simpan hasil ke file JSON (opsional)
return [
'centroid_awal' => $centroidAwalFormatted,
'centroid_akhir' => $centroidAkhirFormatted,
'iterasi' => $iterasi
];
+
}
+
public function hitungKMeansCuranmor()
{
$data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')->orderBy('jumlah_curanmor', 'asc')->get();
@@ -118,22 +131,28 @@ public function hitungKMeansCuranmor()
$k = Klaster::count('id');
$maxIterasi = 100;
- // Ambil centroid awal yang unik
+ // Hitung min dan max untuk normalisasi
$minValue = $data->min('jumlah_curanmor');
$maxValue = $data->max('jumlah_curanmor');
+ // Normalisasi data dan simpan hasilnya ke dalam property baru
+ $normalizedData = $data->map(function ($item) use ($minValue, $maxValue) {
+ $normalized = ($maxValue - $minValue) == 0 ? 0 : ($item->jumlah_curanmor - $minValue) / ($maxValue - $minValue);
+ $item->normalized_curanmor = round($normalized, 2);
+ return $item;
+ });
+
+ // Generate centroid awal unik dari data ter-normalisasi
$generated = collect();
while ($generated->count() < $k) {
- $random = mt_rand($minValue, $maxValue);
- if (!$generated->contains($random)) {
- $generated->push($random);
+ $rand = mt_rand(0, 100) / 100; // antara 0 dan 1 dengan 2 desimal
+ $rand = round($rand, 2);
+ if (!$generated->contains($rand)) {
+ $generated->push($rand);
}
}
- $centroids = $generated->map(function ($value) {
- return ['C' => $value];
- });
-
+ $centroids = $generated->map(fn($val) => ['C' => $val]);
$centroidAwal = $centroids->toArray();
$iterasi = [];
@@ -143,15 +162,20 @@ public function hitungKMeansCuranmor()
$clustered = [];
$currentAssignment = [];
- foreach ($data as $item) {
+ foreach ($normalizedData as $item) {
$jarak = [];
foreach ($centroids as $idx => $centroid) {
- $dist = abs($item->jumlah_curanmor - $centroid['C']);
- $jarak["C" . ($idx + 1)] = $dist;
+ $dist = abs($item->normalized_curanmor - $centroid['C']);
+ $jarak["C" . ($idx + 1)] = round($dist, 2);
}
- $iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
+ // Tambahkan data ke iterasi, termasuk nilai normalisasi
+ $iterasi[$i][] = array_merge(
+ ['kecamatan_id' => $item->kecamatan_id],
+ ['normal' => $item->normalized_curanmor], // tampilkan nilai normalisasi
+ $jarak
+ );
$minIndex = array_keys($jarak, min($jarak))[0];
$clusterNumber = (int) str_replace("C", "", $minIndex);
@@ -167,9 +191,10 @@ public function hitungKMeansCuranmor()
$prevAssignment = $currentAssignment;
- // Update centroid berdasarkan rata-rata
+ // Update centroid berdasarkan rata-rata normalisasi
foreach ($clustered as $key => $group) {
- $avg = collect($group)->avg('jumlah_curanmor');
+ $avg = collect($group)->avg('normalized_curanmor');
+ $avg = round($avg, 2);
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
return $index === ($key - 1)
? ['C' => $avg]
@@ -180,20 +205,17 @@ public function hitungKMeansCuranmor()
// Final mapping centroid ke klaster_id
$finalCentroids = $centroids->map(function ($item, $index) {
- return ['index' => $index + 1, 'C' => $item['C']];
+ return ['index' => $index + 1, 'C' => round($item['C'], 2)];
})->sortBy('C')->values();
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
+ $centroidToKlaster = [];
foreach ($finalCentroids as $i => $centroid) {
$centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
}
-
- // Update ke database
-
-
-
+ // Update database
foreach ($data as $item) {
Curanmor::where('id', $item->id)->update([
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
@@ -202,12 +224,12 @@ public function hitungKMeansCuranmor()
// Format centroid awal
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
- return ['C' . ($index + 1) => $item['C']];
+ return ['C' . ($index + 1) => round($item['C'], 2)];
});
// Format centroid akhir
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
- return ['C' . ($index + 1) => $item['C']];
+ return ['C' . ($index + 1) => round($item['C'], 2)];
});
return [
@@ -217,92 +239,93 @@ public function hitungKMeansCuranmor()
];
}
- public function SSEElbowCuranmor()
+
+ public function SSEElbowCuranmor()
{
$data = Curanmor::select('id', 'jumlah_curanmor')->get();
- $maxK = 10;
+ $maxK = 15;
$maxIterasi = 100;
$elbowData = [];
$min = $data->min('jumlah_curanmor');
$max = $data->max('jumlah_curanmor');
- // Loop untuk setiap nilai k dari 2 hingga maxK
+ // Normalisasi jumlah_curanmor
+ $normalizedData = $data->map(function ($item) use ($min, $max) {
+ $item->normalized = ($max - $min) == 0 ? 0 : round(($item->jumlah_curanmor - $min) / ($max - $min), 2);
+ return $item;
+ });
+
for ($k = 2; $k <= $maxK; $k++) {
$usedValues = [];
$centroids = collect();
+ // Inisialisasi centroid secara acak dari nilai 0 sampai 1 dengan 2 desimal
while ($centroids->count() < $k) {
- $randVal = mt_rand($min, $max);
+ $randVal = round(mt_rand(0, 10000) / 10000, 2); // 2 angka desimal
if (!in_array($randVal, $usedValues)) {
- $centroids->push(['jumlah_curanmor' => $randVal]);
+ $centroids->push(['normalized' => $randVal]);
$usedValues[] = $randVal;
}
}
-
$prevAssignment = [];
for ($iter = 0; $iter < $maxIterasi; $iter++) {
$clustered = [];
$currentAssignment = [];
- foreach ($data as $item) {
+ foreach ($normalizedData as $item) {
$jarak = [];
- // Hitung jarak antara data dan setiap centroid
foreach ($centroids as $idx => $centroid) {
- $dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']);
+ $dist = abs($item->normalized - $centroid['normalized']);
$jarak[$idx] = $dist;
}
- // Tentukan cluster dengan jarak terdekat
$minIndex = array_keys($jarak, min($jarak))[0];
$clustered[$minIndex][] = $item;
$currentAssignment[$item->id] = $minIndex;
}
- // Jika tidak ada perubahan cluster, break
if ($currentAssignment === $prevAssignment) {
break;
}
$prevAssignment = $currentAssignment;
- // Update centroid dengan rata-rata cluster
foreach ($clustered as $key => $group) {
- $avg = collect($group)->avg('jumlah_curanmor');
+ $avg = round(collect($group)->avg('normalized'), 2); // 2 angka desimal
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
return $idx == $key
- ? ['jumlah_curanmor' => $avg]
+ ? ['normalized' => $avg]
: $centroid;
});
}
}
- // Hitung SSE (Sum of Squared Errors)
+ // Hitung SSE
$sse = 0;
foreach ($clustered as $key => $group) {
- $centroidVal = $centroids[$key]['jumlah_curanmor'];
+ $centroidVal = $centroids[$key]['normalized'];
foreach ($group as $item) {
- $sse += pow($item->jumlah_curanmor - $centroidVal, 2);
+ $sse += pow($item->normalized - $centroidVal, 2);
}
}
- // Simpan SSE untuk nilai k
$elbowData[] = [
'k' => $k,
- 'sse' => round($sse, 4)
+ 'sse' => round($sse, 2) // 2 angka desimal
];
}
- // Simpan hasil SSE untuk setiap k ke file JSON
file_put_contents(
storage_path('app/public/sse_elbow_curanmor.json'),
json_encode($elbowData, JSON_PRETTY_PRINT)
);
}
+
public function SSEElbowCuras()
{
$data = Curas::select('id', 'jumlah_curas')->get();
@@ -313,82 +336,84 @@ public function SSEElbowCuras()
$min = $data->min('jumlah_curas');
$max = $data->max('jumlah_curas');
- // Loop untuk setiap nilai k dari 2 hingga maxK
+ // Normalisasi nilai jumlah_curas
+ $normalizedData = $data->map(function ($item) use ($min, $max) {
+ $item->normalized = ($max - $min) == 0 ? 0 : round(($item->jumlah_curas - $min) / ($max - $min), 2);
+ return $item;
+ });
+
for ($k = 2; $k <= $maxK; $k++) {
$usedValues = [];
$centroids = collect();
+ // Inisialisasi centroid secara acak dari nilai 0 sampai 1 dengan 2 desimal
while ($centroids->count() < $k) {
- $randVal = mt_rand($min, $max);
+ $randVal = round(mt_rand(0, 10000) / 10000, 2); // 0.00 - 1.00
if (!in_array($randVal, $usedValues)) {
- $centroids->push(['jumlah_curas' => $randVal]);
+ $centroids->push(['normalized' => $randVal]);
$usedValues[] = $randVal;
}
}
-
$prevAssignment = [];
for ($iter = 0; $iter < $maxIterasi; $iter++) {
$clustered = [];
$currentAssignment = [];
- foreach ($data as $item) {
+ foreach ($normalizedData as $item) {
$jarak = [];
- // Hitung jarak antara data dan setiap centroid
+ // Hitung jarak absolut (Manhattan Distance)
foreach ($centroids as $idx => $centroid) {
- $dist = abs($item->jumlah_curas - $centroid['jumlah_curas']);
+ $dist = abs($item->normalized - $centroid['normalized']);
$jarak[$idx] = $dist;
}
- // Tentukan cluster dengan jarak terdekat
$minIndex = array_keys($jarak, min($jarak))[0];
$clustered[$minIndex][] = $item;
$currentAssignment[$item->id] = $minIndex;
}
- // Jika tidak ada perubahan cluster, break
if ($currentAssignment === $prevAssignment) {
break;
}
$prevAssignment = $currentAssignment;
- // Update centroid dengan rata-rata cluster
+ // Update centroid
foreach ($clustered as $key => $group) {
- $avg = collect($group)->avg('jumlah_curas');
+ $avg = round(collect($group)->avg('normalized'), 2);
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
return $idx == $key
- ? ['jumlah_curas' => $avg]
+ ? ['normalized' => $avg]
: $centroid;
});
}
}
- // Hitung SSE (Sum of Squared Errors)
+ // Hitung SSE
$sse = 0;
foreach ($clustered as $key => $group) {
- $centroidVal = $centroids[$key]['jumlah_curas'];
+ $centroidVal = $centroids[$key]['normalized'];
foreach ($group as $item) {
- $sse += pow($item->jumlah_curas - $centroidVal, 2);
+ $sse += pow($item->normalized - $centroidVal, 2);
}
}
- // Simpan SSE untuk nilai k
$elbowData[] = [
'k' => $k,
- 'sse' => round($sse, 4)
+ 'sse' => round($sse, 2) // dibulatkan ke 2 desimal
];
}
- // Simpan hasil SSE untuk setiap k ke file JSON
file_put_contents(
storage_path('app/public/sse_elbow_curas.json'),
json_encode($elbowData, JSON_PRETTY_PRINT)
);
}
+
public function hitungDBSCANManual()
{
$eps = 1.5; // Jarak maksimum antar titik
diff --git a/resources/views/admin/dashboardListKecamatan.blade.php b/resources/views/admin/dashboardListKecamatan.blade.php
index ab28a64..f092f70 100644
--- a/resources/views/admin/dashboardListKecamatan.blade.php
+++ b/resources/views/admin/dashboardListKecamatan.blade.php
@@ -10,7 +10,7 @@
Kabupaten Probolinggo.
- Tambah Kecamatan
+ {{-- Tambah Kecamatan --}}
@if (session()->has('succes'))
@@ -36,7 +36,7 @@
No
Nama Kecamatan
-
Action
+ {{--
Action --}}
@foreach ( $kecamatans as $kecamatan )
@@ -50,7 +50,7 @@
{{ $kecamatan -> id }}
{{ $kecamatan -> nama_kecamatan }}
-
+ {{--
-
+ --}}
@endforeach
diff --git a/resources/views/admin/dashboardListKlaster.blade.php b/resources/views/admin/dashboardListKlaster.blade.php
index 65c0ab3..9e49e19 100644
--- a/resources/views/admin/dashboardListKlaster.blade.php
+++ b/resources/views/admin/dashboardListKlaster.blade.php
@@ -9,7 +9,6 @@
Berikut merupakan data Klaster atau Kategori yang dijadikan sebagai acuan pemetaan.
Ingat dalam pengisian data klaster, kategori aman atau rendah dimulai dari id 1
- Tambah Klaster
@if (session()->has('succes'))
@@ -36,7 +35,7 @@
id
Nama Klaster
Warna
- Action
+ {{-- Action --}}
@foreach ( $klasters as $klaster )
@@ -51,7 +50,7 @@
{{ $klaster -> id }}
{{ $klaster -> nama_klaster }}
{{ $klaster -> warna }}
-
+ {{--
-
+ --}}
@endforeach
diff --git a/resources/views/components/layoutAdmin.blade.php b/resources/views/components/layoutAdmin.blade.php
index 21a8bdb..7bb6c19 100644
--- a/resources/views/components/layoutAdmin.blade.php
+++ b/resources/views/components/layoutAdmin.blade.php
@@ -56,7 +56,21 @@
Dashboard
-
+
+
+
+ Kecamatan
+
+
+
+
+
+
+
+ Klaster
+
+
+ {{--
Kecamatan
@@ -77,7 +91,7 @@
-
+
@@ -99,7 +113,7 @@
-
+ --}}