fixing kecamatan, klaster, kmeans, sse
This commit is contained in:
parent
ae72f2717e
commit
7cfe92dcec
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
use App\Models\Kecamatan;
|
use App\Models\Kecamatan;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\KMeansService;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
|
||||||
class KecamatanController extends Controller
|
class KecamatanController extends Controller
|
||||||
|
@ -30,14 +32,28 @@ public function create()
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$validateData = $request->validate([
|
||||||
|
'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan',
|
||||||
|
]);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$validateData = $request->validate([
|
DB::beginTransaction();
|
||||||
'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan',
|
|
||||||
]);
|
|
||||||
|
|
||||||
Kecamatan::create($validateData);
|
Kecamatan::create($validateData);
|
||||||
|
|
||||||
|
$serviceKMeans = new KMeansService();
|
||||||
|
$serviceKMeans->SSEElbowCuranmor();
|
||||||
|
$serviceKMeans->SSEElbowCuras();
|
||||||
|
|
||||||
|
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
||||||
|
|
||||||
|
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
return redirect('/dashboard/kecamatan')->with('succes', 'Berhasil Menambahkan Data Kecamatan Baru');
|
return redirect('/dashboard/kecamatan')->with('succes', 'Berhasil Menambahkan Data Kecamatan Baru');
|
||||||
}catch (\Exception $e){
|
}catch (\Exception $e){
|
||||||
|
DB::rollBack();
|
||||||
return redirect('/dashboard/kecamatan')->with('error', 'Gagal Menambahkan Data Kecamatan Baru');
|
return redirect('/dashboard/kecamatan')->with('error', 'Gagal Menambahkan Data Kecamatan Baru');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,14 +87,28 @@ public function edit(Kecamatan $kecamatan)
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, Kecamatan $kecamatan)
|
public function update(Request $request, Kecamatan $kecamatan)
|
||||||
{
|
{
|
||||||
|
$validateData = $request->validate([
|
||||||
|
'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan',
|
||||||
|
]);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$validateData = $request->validate([
|
DB::beginTransaction();
|
||||||
'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan',
|
|
||||||
]);
|
|
||||||
|
|
||||||
Kecamatan::where('id', $kecamatan->id)->update($validateData);
|
Kecamatan::where('id', $kecamatan->id)->update($validateData);
|
||||||
|
|
||||||
|
$serviceKMeans = new KMeansService();
|
||||||
|
$serviceKMeans->SSEElbowCuranmor();
|
||||||
|
$serviceKMeans->SSEElbowCuras();
|
||||||
|
|
||||||
|
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
||||||
|
|
||||||
|
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Ubah');
|
return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Ubah');
|
||||||
}catch (\Exception $e){
|
}catch (\Exception $e){
|
||||||
|
DB::rollBack();
|
||||||
return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan Gagal Di Ubah');
|
return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan Gagal Di Ubah');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +121,24 @@ public function update(Request $request, Kecamatan $kecamatan)
|
||||||
public function destroy(Kecamatan $kecamatan)
|
public function destroy(Kecamatan $kecamatan)
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
|
DB::beginTransaction();
|
||||||
Kecamatan::destroy($kecamatan->id);
|
Kecamatan::destroy($kecamatan->id);
|
||||||
|
|
||||||
|
$serviceKMeans = new KMeansService();
|
||||||
|
$serviceKMeans->SSEElbowCuranmor();
|
||||||
|
$serviceKMeans->SSEElbowCuras();
|
||||||
|
|
||||||
|
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
||||||
|
|
||||||
|
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Hapus');
|
return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Hapus');
|
||||||
|
|
||||||
}catch (\Exception $e){
|
}catch (\Exception $e){
|
||||||
|
DB::rollBack();
|
||||||
return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan '. $kecamatan->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Kecamatan '. $kecamatan->nama_kecamatan.' Terlebih Dahulu');
|
return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan '. $kecamatan->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Kecamatan '. $kecamatan->nama_kecamatan.' Terlebih Dahulu');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use App\Models\Klaster;
|
use App\Models\Klaster;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Services\KMeansService;
|
use App\Services\KMeansService;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class KlasterController extends Controller
|
class KlasterController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -29,30 +30,35 @@ public function create()
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$validateData = $request->validate([
|
||||||
|
'nama_klaster' =>'required|max:255|unique:klasters,nama_klaster',
|
||||||
|
'warna' =>'required|max:255',
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$validateData = $request->validate([
|
|
||||||
'nama_klaster' =>'required|max:255|unique:klasters,nama_klaster',
|
Klaster::create($validateData);
|
||||||
'warna' =>'required|max:255',
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
|
||||||
$serviceKMeans = new KMeansService();
|
$serviceKMeans = new KMeansService();
|
||||||
$serviceKMeans->SSEElbowCuranmor();
|
$serviceKMeans->SSEElbowCuranmor();
|
||||||
$serviceKMeans->SSEElbowCuras();
|
$serviceKMeans->SSEElbowCuras();
|
||||||
|
|
||||||
$serviceKMeansCuras = new KMeansService();
|
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
|
||||||
$hasilKMeansCuras = $serviceKMeansCuras->hitungKMeansCuras();
|
|
||||||
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
||||||
|
|
||||||
$serviceKmeansCuranmor = new KMeansService();
|
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
|
||||||
$hasilKMeansCuranmor = $serviceKmeansCuranmor->hitungKMeansCuranmor();
|
|
||||||
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
||||||
|
|
||||||
Klaster::create($validateData);
|
DB::commit();
|
||||||
|
|
||||||
return redirect('/dashboard/klaster')->with('succes', 'Berhasil Menambahkan Klaster Baru');
|
return redirect('/dashboard/klaster')->with('succes', 'Berhasil Menambahkan Klaster Baru');
|
||||||
}catch (\Exception $e){
|
}catch (\Exception $e){
|
||||||
|
|
||||||
|
DB::rollBack();
|
||||||
|
|
||||||
return redirect('/dashboard/klaster')->with('error', 'Gagal Menambahkan Klaster Baru ' .$e->getMessage());
|
return redirect('/dashboard/klaster')->with('error', 'Gagal Menambahkan Klaster Baru ' .$e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,17 +91,32 @@ public function edit(Klaster $klaster)
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, Klaster $klaster)
|
public function update(Request $request, Klaster $klaster)
|
||||||
{
|
{
|
||||||
|
$validateData = $request->validate([
|
||||||
|
'nama_klaster' => 'sometimes|required|max:255|unique:klasters,nama_klaster,' . $klaster->id,
|
||||||
|
'warna' => 'sometimes|required|max:255',
|
||||||
|
]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$validateData = $request->validate([
|
DB::beginTransaction();
|
||||||
'nama_klaster' => 'sometimes|required|max:255|unique:klasters,nama_klaster,' . $klaster->id,
|
|
||||||
'warna' => 'sometimes|required|max:255',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Hanya update data yang diisi (tidak mengganti dengan null)
|
// Hanya update data yang diisi (tidak mengganti dengan null)
|
||||||
Klaster::where('id', $klaster->id)->update(array_filter($validateData));
|
Klaster::where('id', $klaster->id)->update(array_filter($validateData));
|
||||||
|
|
||||||
|
$serviceKMeans = new KMeansService();
|
||||||
|
$serviceKMeans->SSEElbowCuranmor();
|
||||||
|
$serviceKMeans->SSEElbowCuras();
|
||||||
|
|
||||||
|
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
||||||
|
|
||||||
|
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
return redirect('/dashboard/klaster')->with('success', 'Data Klaster Berhasil Diubah');
|
return redirect('/dashboard/klaster')->with('success', 'Data Klaster Berhasil Diubah');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
DB::rollBack();
|
||||||
return redirect('/dashboard/klaster')->with('error', 'Data Klaster Gagal Diubah');
|
return redirect('/dashboard/klaster')->with('error', 'Data Klaster Gagal Diubah');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,11 +128,27 @@ public function update(Request $request, Klaster $klaster)
|
||||||
public function destroy(Klaster $klaster)
|
public function destroy(Klaster $klaster)
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
Klaster::destroy($klaster->id);
|
Klaster::destroy($klaster->id);
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
$serviceKMeans = new KMeansService();
|
||||||
|
$serviceKMeans->SSEElbowCuranmor();
|
||||||
|
$serviceKMeans->SSEElbowCuras();
|
||||||
|
|
||||||
|
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
|
||||||
|
|
||||||
|
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
|
||||||
|
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
|
||||||
|
|
||||||
return redirect('/dashboard/klaster')->with('succes', 'Data Klaster Berhasil Di Hapus');
|
return redirect('/dashboard/klaster')->with('succes', 'Data Klaster Berhasil Di Hapus');
|
||||||
|
|
||||||
}catch (\Exception $e){
|
}catch (\Exception $e){
|
||||||
return redirect('/dashboard/klaster')->with('error', 'Data Klaster '. $klaster->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Klaster '. $klaster->nama_kecamatan.' Terlebih Dahulu');
|
|
||||||
|
DB::rollBack();
|
||||||
|
return redirect('/dashboard/klaster')->with('error', 'Data Klaster '. $klaster->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Klaster '. $klaster->nama_kecamatan.' Terlebih Dahulu '. $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,23 +13,14 @@ public function KMeansCuras()
|
||||||
{
|
{
|
||||||
$data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')->orderBy('jumlah_curas', 'asc')->get();
|
$data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')->orderBy('jumlah_curas', 'asc')->get();
|
||||||
|
|
||||||
$k = Klaster::count('id');
|
|
||||||
$maxIterasi = 100;
|
$maxIterasi = 100;
|
||||||
|
|
||||||
$uniqueCount = $data->unique('jumlah_curas')->count();
|
|
||||||
if ($uniqueCount < $k) {
|
|
||||||
throw new \Exception("Jumlah nilai unik pada 'jumlah_curas' ($uniqueCount) kurang dari jumlah klaster ($k). Pastikan data memiliki variasi yang cukup.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ambil centroid awal yang unik
|
$centroidManual = [0, 1, 3];
|
||||||
// Gunakan centroid tetap
|
$centroids = collect($centroidManual)->map(function ($value) {
|
||||||
|
return ['C' => $value];
|
||||||
$centroidValues = [0, 1, 3];
|
|
||||||
$centroids = collect($centroidValues)->map(function ($val) {
|
|
||||||
return ['jumlah_curas' => $val];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Simpan centroid awal sebelum iterasi
|
|
||||||
$centroidAwal = $centroids->toArray();
|
$centroidAwal = $centroids->toArray();
|
||||||
|
|
||||||
$iterasi = [];
|
$iterasi = [];
|
||||||
|
@ -43,13 +34,13 @@ public function KMeansCuras()
|
||||||
$jarak = [];
|
$jarak = [];
|
||||||
|
|
||||||
foreach ($centroids as $idx => $centroid) {
|
foreach ($centroids as $idx => $centroid) {
|
||||||
$dist = abs($item->jumlah_curas - $centroid['jumlah_curas']);
|
$dist = abs($item->jumlah_curas - $centroid['C']);
|
||||||
$jarak["C" . ($idx + 1)] = $dist;
|
$jarak["C" . ($idx + 1)] = $dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
|
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
|
||||||
|
|
||||||
$minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2"
|
$minIndex = array_keys($jarak, min($jarak))[0];
|
||||||
$clusterNumber = (int) str_replace("C", "", $minIndex);
|
$clusterNumber = (int) str_replace("C", "", $minIndex);
|
||||||
|
|
||||||
$clustered[$clusterNumber][] = $item;
|
$clustered[$clusterNumber][] = $item;
|
||||||
|
@ -57,65 +48,64 @@ public function KMeansCuras()
|
||||||
$currentAssignment[$item->id] = $clusterNumber;
|
$currentAssignment[$item->id] = $clusterNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break
|
|
||||||
if ($currentAssignment === $prevAssignment) {
|
if ($currentAssignment === $prevAssignment) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$prevAssignment = $currentAssignment;
|
$prevAssignment = $currentAssignment;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Update centroid berdasarkan rata-rata
|
// Update centroid berdasarkan rata-rata
|
||||||
foreach ($clustered as $key => $group) {
|
foreach ($clustered as $key => $group) {
|
||||||
$avg = collect($group)->avg('jumlah_curas');
|
$avg = collect($group)->avg('jumlah_curas');
|
||||||
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
||||||
return $index === ($key - 1)
|
return $index === ($key - 1)
|
||||||
? ['jumlah_curas' => $avg]
|
? ['C' => $avg]
|
||||||
: $item;
|
: $item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Final mapping centroid ke klaster_id (aman/sedang/rawan)
|
// Final mapping centroid ke klaster_id
|
||||||
$finalCentroids = $centroids->map(function ($item, $index) {
|
$finalCentroids = $centroids->map(function ($item, $index) {
|
||||||
return ['index' => $index + 1, 'jumlah_curas' => $item['jumlah_curas']];
|
return ['index' => $index + 1, 'C' => $item['C']];
|
||||||
})->sortBy('jumlah_curas')->values();
|
})->sortBy('C')->values();
|
||||||
|
|
||||||
$centroidToKlaster = [];
|
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
|
||||||
|
|
||||||
foreach ($finalCentroids as $i => $centroid) {
|
foreach ($finalCentroids as $i => $centroid) {
|
||||||
// Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...)
|
$centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
|
||||||
$centroidToKlaster[$centroid['index']] = $i + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update ke database
|
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
Curas::where('id', $item->id)->update([
|
Curas::where('id', $item->id)->update([
|
||||||
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format centroid awal
|
||||||
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
||||||
return ['C' . ($index + 1) => $item['jumlah_curas']];
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$hasil = [
|
// Format centroid akhir
|
||||||
|
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
|
||||||
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
|
});
|
||||||
|
|
||||||
|
$hasilKMeansCuras = [
|
||||||
'centroid_awal' => $centroidAwalFormatted,
|
'centroid_awal' => $centroidAwalFormatted,
|
||||||
|
'centroid_akhir' => $centroidAkhirFormatted,
|
||||||
'iterasi' => $iterasi
|
'iterasi' => $iterasi
|
||||||
];
|
];
|
||||||
|
|
||||||
file_put_contents(
|
file_put_contents(
|
||||||
storage_path('app/public/hasil_kmeans_curas.json'),
|
storage_path('app/public/hasil_kmeans_curas.json'),
|
||||||
json_encode($hasil, JSON_PRETTY_PRINT)
|
json_encode($hasilKMeansCuras, JSON_PRETTY_PRINT)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return redirect('/dashboard/TampilHitungCuras');
|
return redirect('/dashboard/TampilHitungCuras');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,20 +113,13 @@ public function KMeansCuranmor()
|
||||||
{
|
{
|
||||||
$data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')->orderBy('jumlah_curanmor', 'asc')->get();
|
$data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')->orderBy('jumlah_curanmor', 'asc')->get();
|
||||||
|
|
||||||
$k = Klaster::count('id');
|
|
||||||
$maxIterasi = 100;
|
$maxIterasi = 100;
|
||||||
|
|
||||||
$uniqueCount = $data->unique('jumlah_curanmor')->count();
|
$centroidManual = [10, 20, 30];
|
||||||
if ($uniqueCount < $k) {
|
$centroids = collect($centroidManual)->map(function ($value) {
|
||||||
throw new \Exception("Jumlah nilai unik pada 'jumlah_curanmor' ($uniqueCount) kurang dari jumlah klaster ($k). Pastikan data memiliki variasi yang cukup.");
|
return ['C' => $value];
|
||||||
}
|
|
||||||
|
|
||||||
$centroidValues = [10, 20, 30];
|
|
||||||
$centroids = collect($centroidValues)->map(function ($val) {
|
|
||||||
return ['jumlah_curanmor' => $val];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Simpan centroid awal sebelum iterasi
|
|
||||||
$centroidAwal = $centroids->toArray();
|
$centroidAwal = $centroids->toArray();
|
||||||
|
|
||||||
$iterasi = [];
|
$iterasi = [];
|
||||||
|
@ -148,82 +131,84 @@ public function KMeansCuranmor()
|
||||||
|
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
$jarak = [];
|
$jarak = [];
|
||||||
|
|
||||||
foreach ($centroids as $idx => $centroid) {
|
foreach ($centroids as $idx => $centroid) {
|
||||||
// Menggunakan Euclidean distance standar (akar kuadrat dari selisih kuadrat)
|
$dist = abs($item->jumlah_curanmor - $centroid['C']);
|
||||||
$dist = sqrt(pow($item->jumlah_curanmor - $centroid['jumlah_curanmor'], 2));
|
|
||||||
$jarak["C" . ($idx + 1)] = $dist;
|
$jarak["C" . ($idx + 1)] = $dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
|
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
|
||||||
|
|
||||||
$minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2"
|
$minIndex = array_keys($jarak, min($jarak))[0];
|
||||||
$clusterNumber = (int) str_replace("C", "", $minIndex);
|
$clusterNumber = (int) str_replace("C", "", $minIndex);
|
||||||
|
|
||||||
$clustered[$clusterNumber][] = $item;
|
$clustered[$clusterNumber][] = $item;
|
||||||
$item->temp_klaster = $clusterNumber;
|
$item->temp_klaster = $clusterNumber;
|
||||||
$currentAssignment[$item->id] = $clusterNumber;
|
$currentAssignment[$item->id] = $clusterNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break
|
|
||||||
if ($currentAssignment === $prevAssignment) {
|
if ($currentAssignment === $prevAssignment) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$prevAssignment = $currentAssignment;
|
$prevAssignment = $currentAssignment;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Update centroid berdasarkan rata-rata
|
// Update centroid berdasarkan rata-rata
|
||||||
foreach ($clustered as $key => $group) {
|
foreach ($clustered as $key => $group) {
|
||||||
$avg = collect($group)->avg('jumlah_curanmor');
|
$avg = collect($group)->avg('jumlah_curanmor');
|
||||||
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
||||||
return $index === ($key - 1)
|
return $index === ($key - 1)
|
||||||
? ['jumlah_curanmor' => $avg]
|
? ['C' => $avg]
|
||||||
: $item;
|
: $item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Final mapping centroid ke klaster_id (aman/sedang/rawan)
|
// Final mapping centroid ke klaster_id
|
||||||
$finalCentroids = $centroids->map(function ($item, $index) {
|
$finalCentroids = $centroids->map(function ($item, $index) {
|
||||||
return ['index' => $index + 1, 'jumlah_curanmor' => $item['jumlah_curanmor']];
|
return ['index' => $index + 1, 'C' => $item['C']];
|
||||||
})->sortBy('jumlah_curanmor')->values();
|
})->sortBy('C')->values();
|
||||||
|
|
||||||
$centroidToKlaster = [];
|
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
|
||||||
|
|
||||||
foreach ($finalCentroids as $i => $centroid) {
|
foreach ($finalCentroids as $i => $centroid) {
|
||||||
// Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...)
|
$centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
|
||||||
$centroidToKlaster[$centroid['index']] = $i + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update ke database
|
// Update ke database
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
Curanmor::where('id', $item->id)->update([
|
Curanmor::where('id', $item->id)->update([
|
||||||
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format centroid awal
|
||||||
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
||||||
return ['C' . ($index + 1) => $item['jumlah_curanmor']];
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
});
|
});
|
||||||
|
|
||||||
$hasil = [
|
// Format centroid akhir
|
||||||
|
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
|
||||||
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
|
});
|
||||||
|
|
||||||
|
$hasilKMeansCuranmor = [
|
||||||
'centroid_awal' => $centroidAwalFormatted,
|
'centroid_awal' => $centroidAwalFormatted,
|
||||||
|
'centroid_akhir' => $centroidAkhirFormatted,
|
||||||
'iterasi' => $iterasi
|
'iterasi' => $iterasi
|
||||||
];
|
];
|
||||||
|
|
||||||
file_put_contents(
|
file_put_contents(
|
||||||
storage_path('app/public/hasil_kmeans_curanmor.json'),
|
storage_path('app/public/hasil_kmeans_curanmor.json'),
|
||||||
json_encode($hasil, JSON_PRETTY_PRINT)
|
json_encode($hasilKMeansCuranmor, JSON_PRETTY_PRINT)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return redirect('/dashboard/TampilHitungCuranmor');
|
return redirect('/dashboard/TampilHitungCuranmor');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,16 @@ public function hitungKMeansCuras()
|
||||||
|
|
||||||
$generated = collect();
|
$generated = collect();
|
||||||
while ($generated->count() < $k) {
|
while ($generated->count() < $k) {
|
||||||
$randomFloat = round(mt_rand($minValue * 100, $maxValue * 100) / 100, 2);
|
$random = mt_rand($minValue, $maxValue);
|
||||||
if (!$generated->contains($randomFloat)) {
|
if (!$generated->contains($random)) {
|
||||||
$generated->push($randomFloat);
|
$generated->push($random);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$centroids = $generated->map(function ($value) {
|
$centroids = $generated->map(function ($value) {
|
||||||
return ['jumlah_curas' => $value];
|
return ['C' => $value];
|
||||||
});
|
});
|
||||||
|
|
||||||
$centroidAwal = $centroids->toArray();
|
$centroidAwal = $centroids->toArray();
|
||||||
|
|
||||||
$iterasi = [];
|
$iterasi = [];
|
||||||
|
@ -43,7 +44,7 @@ public function hitungKMeansCuras()
|
||||||
$jarak = [];
|
$jarak = [];
|
||||||
|
|
||||||
foreach ($centroids as $idx => $centroid) {
|
foreach ($centroids as $idx => $centroid) {
|
||||||
$dist = abs($item->jumlah_curas - $centroid['jumlah_curas']);
|
$dist = abs($item->jumlah_curas - $centroid['C']);
|
||||||
$jarak["C" . ($idx + 1)] = $dist;
|
$jarak["C" . ($idx + 1)] = $dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ public function hitungKMeansCuras()
|
||||||
$avg = collect($group)->avg('jumlah_curas');
|
$avg = collect($group)->avg('jumlah_curas');
|
||||||
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
||||||
return $index === ($key - 1)
|
return $index === ($key - 1)
|
||||||
? ['jumlah_curas' => $avg]
|
? ['C' => $avg]
|
||||||
: $item;
|
: $item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -76,15 +77,20 @@ public function hitungKMeansCuras()
|
||||||
|
|
||||||
// Final mapping centroid ke klaster_id
|
// Final mapping centroid ke klaster_id
|
||||||
$finalCentroids = $centroids->map(function ($item, $index) {
|
$finalCentroids = $centroids->map(function ($item, $index) {
|
||||||
return ['index' => $index + 1, 'jumlah_curas' => $item['jumlah_curas']];
|
return ['index' => $index + 1, 'C' => $item['C']];
|
||||||
})->sortBy('jumlah_curas')->values();
|
})->sortBy('C')->values();
|
||||||
|
|
||||||
|
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
|
||||||
|
|
||||||
$centroidToKlaster = [];
|
|
||||||
foreach ($finalCentroids as $i => $centroid) {
|
foreach ($finalCentroids as $i => $centroid) {
|
||||||
$centroidToKlaster[$centroid['index']] = $i + 1;
|
$centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update ke database
|
// Update ke database
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
Curas::where('id', $item->id)->update([
|
Curas::where('id', $item->id)->update([
|
||||||
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
||||||
|
@ -93,12 +99,12 @@ public function hitungKMeansCuras()
|
||||||
|
|
||||||
// Format centroid awal
|
// Format centroid awal
|
||||||
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
||||||
return ['C' . ($index + 1) => $item['jumlah_curas']];
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
});
|
});
|
||||||
|
|
||||||
// Format centroid akhir
|
// Format centroid akhir
|
||||||
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
|
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
|
||||||
return ['C' . ($index + 1) => $item['jumlah_curas']];
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
});
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -115,20 +121,22 @@ public function hitungKMeansCuranmor()
|
||||||
$k = Klaster::count('id');
|
$k = Klaster::count('id');
|
||||||
$maxIterasi = 100;
|
$maxIterasi = 100;
|
||||||
|
|
||||||
|
// Ambil centroid awal yang unik
|
||||||
$minValue = $data->min('jumlah_curanmor');
|
$minValue = $data->min('jumlah_curanmor');
|
||||||
$maxValue = $data->max('jumlah_curanmor');
|
$maxValue = $data->max('jumlah_curanmor');
|
||||||
|
|
||||||
$generated = collect();
|
$generated = collect();
|
||||||
while ($generated->count() < $k) {
|
while ($generated->count() < $k) {
|
||||||
$randomFloat = round(mt_rand($minValue * 100, $maxValue * 100) / 100, 2);
|
$random = mt_rand($minValue, $maxValue);
|
||||||
if (!$generated->contains($randomFloat)) {
|
if (!$generated->contains($random)) {
|
||||||
$generated->push($randomFloat);
|
$generated->push($random);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$centroids = $generated->map(function ($value) {
|
$centroids = $generated->map(function ($value) {
|
||||||
return ['jumlah_curanmor' => $value];
|
return ['C' => $value];
|
||||||
});
|
});
|
||||||
|
|
||||||
$centroidAwal = $centroids->toArray();
|
$centroidAwal = $centroids->toArray();
|
||||||
|
|
||||||
$iterasi = [];
|
$iterasi = [];
|
||||||
|
@ -142,13 +150,13 @@ public function hitungKMeansCuranmor()
|
||||||
$jarak = [];
|
$jarak = [];
|
||||||
|
|
||||||
foreach ($centroids as $idx => $centroid) {
|
foreach ($centroids as $idx => $centroid) {
|
||||||
$dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']);
|
$dist = abs($item->jumlah_curanmor - $centroid['C']);
|
||||||
$jarak["C" . ($idx + 1)] = $dist;
|
$jarak["C" . ($idx + 1)] = $dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
|
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak);
|
||||||
|
|
||||||
$minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2"
|
$minIndex = array_keys($jarak, min($jarak))[0];
|
||||||
$clusterNumber = (int) str_replace("C", "", $minIndex);
|
$clusterNumber = (int) str_replace("C", "", $minIndex);
|
||||||
|
|
||||||
$clustered[$clusterNumber][] = $item;
|
$clustered[$clusterNumber][] = $item;
|
||||||
|
@ -156,77 +164,78 @@ public function hitungKMeansCuranmor()
|
||||||
$currentAssignment[$item->id] = $clusterNumber;
|
$currentAssignment[$item->id] = $clusterNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break
|
|
||||||
if ($currentAssignment === $prevAssignment) {
|
if ($currentAssignment === $prevAssignment) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$prevAssignment = $currentAssignment;
|
$prevAssignment = $currentAssignment;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Update centroid berdasarkan rata-rata
|
// Update centroid berdasarkan rata-rata
|
||||||
foreach ($clustered as $key => $group) {
|
foreach ($clustered as $key => $group) {
|
||||||
$avg = collect($group)->avg('jumlah_curanmor');
|
$avg = collect($group)->avg('jumlah_curanmor');
|
||||||
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
|
||||||
return $index === ($key - 1)
|
return $index === ($key - 1)
|
||||||
? ['jumlah_curanmor' => $avg]
|
? ['C' => $avg]
|
||||||
: $item;
|
: $item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Final mapping centroid ke klaster_id (aman/sedang/rawan)
|
// Final mapping centroid ke klaster_id
|
||||||
$finalCentroids = $centroids->map(function ($item, $index) {
|
$finalCentroids = $centroids->map(function ($item, $index) {
|
||||||
return ['index' => $index + 1, 'jumlah_curanmor' => $item['jumlah_curanmor']];
|
return ['index' => $index + 1, 'C' => $item['C']];
|
||||||
})->sortBy('jumlah_curanmor')->values();
|
})->sortBy('C')->values();
|
||||||
|
|
||||||
$centroidToKlaster = [];
|
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
|
||||||
|
|
||||||
foreach ($finalCentroids as $i => $centroid) {
|
foreach ($finalCentroids as $i => $centroid) {
|
||||||
// Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...)
|
$centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
|
||||||
$centroidToKlaster[$centroid['index']] = $i + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update ke database
|
// Update ke database
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
Curanmor::where('id', $item->id)->update([
|
Curanmor::where('id', $item->id)->update([
|
||||||
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
'klaster_id' => $centroidToKlaster[$item->temp_klaster],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format centroid awal
|
||||||
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
|
||||||
return ['C' . ($index + 1) => $item['jumlah_curanmor']];
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Format centroid akhir
|
||||||
|
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
|
||||||
|
return ['C' . ($index + 1) => $item['C']];
|
||||||
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'centroid_awal' => $centroidAwalFormatted,
|
'centroid_awal' => $centroidAwalFormatted,
|
||||||
|
'centroid_akhir' => $centroidAkhirFormatted,
|
||||||
'iterasi' => $iterasi
|
'iterasi' => $iterasi
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SSEElbowCuras()
|
public function SSEElbowCuranmor()
|
||||||
{
|
{
|
||||||
$data = Curas::select('id', 'jumlah_curas')->get();
|
$data = Curanmor::select('id', 'jumlah_curanmor')->get();
|
||||||
$maxK = 10;
|
$maxK = 10;
|
||||||
$maxIterasi = 100;
|
$maxIterasi = 100;
|
||||||
$elbowData = [];
|
$elbowData = [];
|
||||||
|
|
||||||
// Ambil nilai minimum dan maksimum dari jumlah_curas
|
$min = $data->min('jumlah_curanmor');
|
||||||
$min = $data->min('jumlah_curas');
|
$max = $data->max('jumlah_curanmor');
|
||||||
$max = $data->max('jumlah_curas');
|
|
||||||
|
|
||||||
|
// Loop untuk setiap nilai k dari 2 hingga maxK
|
||||||
for ($k = 2; $k <= $maxK; $k++) {
|
for ($k = 2; $k <= $maxK; $k++) {
|
||||||
// Inisialisasi centroid awal sebagai float acak dalam rentang min-max
|
|
||||||
$centroids = collect(range(1, $k))->map(function () use ($min, $max) {
|
$centroids = collect(range(1, $k))->map(function () use ($min, $max) {
|
||||||
return ['jumlah_curas' => mt_rand($min * 100, $max * 100) / 100];
|
return ['jumlah_curanmor' => mt_rand($min, $max)];
|
||||||
});
|
});
|
||||||
|
|
||||||
$centroidAwal = $centroids->pluck('jumlah_curas')->toArray();
|
|
||||||
$prevAssignment = [];
|
$prevAssignment = [];
|
||||||
|
|
||||||
for ($iter = 0; $iter < $maxIterasi; $iter++) {
|
for ($iter = 0; $iter < $maxIterasi; $iter++) {
|
||||||
|
@ -236,22 +245,104 @@ public function SSEElbowCuras()
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
$jarak = [];
|
$jarak = [];
|
||||||
|
|
||||||
|
// Hitung jarak antara data dan setiap centroid
|
||||||
foreach ($centroids as $idx => $centroid) {
|
foreach ($centroids as $idx => $centroid) {
|
||||||
$dist = abs($item->jumlah_curas - $centroid['jumlah_curas']);
|
$dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']);
|
||||||
$jarak[$idx] = $dist;
|
$jarak[$idx] = $dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tentukan cluster dengan jarak terdekat
|
||||||
$minIndex = array_keys($jarak, min($jarak))[0];
|
$minIndex = array_keys($jarak, min($jarak))[0];
|
||||||
$clustered[$minIndex][] = $item;
|
$clustered[$minIndex][] = $item;
|
||||||
$currentAssignment[$item->id] = $minIndex;
|
$currentAssignment[$item->id] = $minIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jika tidak ada perubahan cluster, break
|
||||||
if ($currentAssignment === $prevAssignment) {
|
if ($currentAssignment === $prevAssignment) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$prevAssignment = $currentAssignment;
|
$prevAssignment = $currentAssignment;
|
||||||
|
|
||||||
|
// Update centroid dengan rata-rata cluster
|
||||||
|
foreach ($clustered as $key => $group) {
|
||||||
|
$avg = collect($group)->avg('jumlah_curanmor');
|
||||||
|
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
|
||||||
|
return $idx == $key
|
||||||
|
? ['jumlah_curanmor' => $avg]
|
||||||
|
: $centroid;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hitung SSE (Sum of Squared Errors)
|
||||||
|
$sse = 0;
|
||||||
|
foreach ($clustered as $key => $group) {
|
||||||
|
$centroidVal = $centroids[$key]['jumlah_curanmor'];
|
||||||
|
foreach ($group as $item) {
|
||||||
|
$sse += pow($item->jumlah_curanmor - $centroidVal, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan SSE untuk nilai k
|
||||||
|
$elbowData[] = [
|
||||||
|
'k' => $k,
|
||||||
|
'sse' => round($sse, 4)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
$maxK = 10;
|
||||||
|
$maxIterasi = 100;
|
||||||
|
$elbowData = [];
|
||||||
|
|
||||||
|
$min = $data->min('jumlah_curas');
|
||||||
|
$max = $data->max('jumlah_curas');
|
||||||
|
|
||||||
|
// Loop untuk setiap nilai k dari 2 hingga maxK
|
||||||
|
for ($k = 2; $k <= $maxK; $k++) {
|
||||||
|
$centroids = collect(range(1, $k))->map(function () use ($min, $max) {
|
||||||
|
return ['jumlah_curas' => mt_rand($min, $max)];
|
||||||
|
});
|
||||||
|
|
||||||
|
$prevAssignment = [];
|
||||||
|
|
||||||
|
for ($iter = 0; $iter < $maxIterasi; $iter++) {
|
||||||
|
$clustered = [];
|
||||||
|
$currentAssignment = [];
|
||||||
|
|
||||||
|
foreach ($data as $item) {
|
||||||
|
$jarak = [];
|
||||||
|
|
||||||
|
// Hitung jarak antara data dan setiap centroid
|
||||||
|
foreach ($centroids as $idx => $centroid) {
|
||||||
|
$dist = abs($item->jumlah_curas - $centroid['jumlah_curas']);
|
||||||
|
$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) {
|
foreach ($clustered as $key => $group) {
|
||||||
$avg = collect($group)->avg('jumlah_curas');
|
$avg = collect($group)->avg('jumlah_curas');
|
||||||
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
|
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
|
||||||
|
@ -262,7 +353,7 @@ public function SSEElbowCuras()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitung SSE
|
// Hitung SSE (Sum of Squared Errors)
|
||||||
$sse = 0;
|
$sse = 0;
|
||||||
foreach ($clustered as $key => $group) {
|
foreach ($clustered as $key => $group) {
|
||||||
$centroidVal = $centroids[$key]['jumlah_curas'];
|
$centroidVal = $centroids[$key]['jumlah_curas'];
|
||||||
|
@ -271,96 +362,22 @@ public function SSEElbowCuras()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simpan SSE untuk nilai k
|
||||||
$elbowData[] = [
|
$elbowData[] = [
|
||||||
'k' => $k,
|
'k' => $k,
|
||||||
'sse' => $sse,
|
'sse' => round($sse, 4)
|
||||||
'centroid_awal' => $centroidAwal
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simpan hasil SSE untuk setiap k ke file JSON
|
||||||
|
|
||||||
file_put_contents(
|
file_put_contents(
|
||||||
storage_path('app/public/sse_elbow_curas.json'),
|
storage_path('app/public/sse_elbow_curas.json'),
|
||||||
json_encode($elbowData, JSON_PRETTY_PRINT)
|
json_encode($elbowData, JSON_PRETTY_PRINT)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function SSEElbowCuranmor()
|
|
||||||
{
|
|
||||||
$data = Curanmor::select('id', 'jumlah_curanmor')->get();
|
|
||||||
$maxK = 10;
|
|
||||||
$maxIterasi = 100;
|
|
||||||
$elbowData = [];
|
|
||||||
|
|
||||||
for ($k = 2; $k <= $maxK; $k++) {
|
|
||||||
// Inisialisasi centroid awal secara acak
|
|
||||||
$centroids = $data->unique('jumlah_curanmor')->shuffle()->take($k)->values()->map(function ($item) {
|
|
||||||
return ['jumlah_curanmor' => $item->jumlah_curanmor];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Simpan centroid awal sebagai array angka
|
|
||||||
$centroidAwal = $centroids->pluck('jumlah_curanmor')->toArray();
|
|
||||||
|
|
||||||
$prevAssignment = [];
|
|
||||||
|
|
||||||
for ($iter = 0; $iter < $maxIterasi; $iter++) {
|
|
||||||
$clustered = [];
|
|
||||||
$currentAssignment = [];
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$jarak = [];
|
|
||||||
|
|
||||||
foreach ($centroids as $idx => $centroid) {
|
|
||||||
$dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']);
|
|
||||||
$jarak[$idx] = $dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
$minIndex = array_keys($jarak, min($jarak))[0];
|
|
||||||
$clustered[$minIndex][] = $item;
|
|
||||||
$currentAssignment[$item->id] = $minIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($currentAssignment === $prevAssignment) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$prevAssignment = $currentAssignment;
|
|
||||||
|
|
||||||
// Update centroid
|
|
||||||
foreach ($clustered as $key => $group) {
|
|
||||||
$avg = collect($group)->avg('jumlah_curanmor');
|
|
||||||
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
|
|
||||||
return $idx == $key
|
|
||||||
? ['jumlah_curanmor' => $avg]
|
|
||||||
: $centroid;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hitung SSE untuk k saat ini
|
|
||||||
$sse = 0;
|
|
||||||
foreach ($clustered as $key => $group) {
|
|
||||||
$centroidVal = $centroids[$key]['jumlah_curanmor'];
|
|
||||||
foreach ($group as $item) {
|
|
||||||
$sse += pow($item->jumlah_curanmor - $centroidVal, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$elbowData[] = [
|
|
||||||
'k' => $k,
|
|
||||||
'sse' => $sse,
|
|
||||||
'centroid_awal' => $centroidAwal
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simpan ke file
|
|
||||||
file_put_contents(
|
|
||||||
storage_path('app/public/sse_elbow_curanmor.json'),
|
|
||||||
json_encode($elbowData, JSON_PRETTY_PRINT)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public function up(): void
|
||||||
table: 'kecamatans', indexName: 'curas_kecamatan_id');
|
table: 'kecamatans', indexName: 'curas_kecamatan_id');
|
||||||
$table->float('jumlah_curas');
|
$table->float('jumlah_curas');
|
||||||
$table->foreignId('klaster_id')->nullable()->constrained(
|
$table->foreignId('klaster_id')->nullable()->constrained(
|
||||||
table: 'klasters', indexName: 'curas_klaster_id');
|
table: 'klasters', indexName: 'curas_klaster_id')->nullOnDelete();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public function up(): void
|
||||||
table: 'kecamatans', indexName: 'curanmor_kecamatan_id');
|
table: 'kecamatans', indexName: 'curanmor_kecamatan_id');
|
||||||
$table->float('jumlah_curanmor');
|
$table->float('jumlah_curanmor');
|
||||||
$table->foreignId('klaster_id')->nullable()->constrained(
|
$table->foreignId('klaster_id')->nullable()->constrained(
|
||||||
table: 'klasters', indexName: 'klaster_kecamatan_id');
|
table: 'klasters', indexName: 'klaster_kecamatan_id')->nullOnDelete();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5213,12 +5213,11 @@ if (jQuery("#editor").length) {
|
||||||
valueAxis.title.text = "Nilai SSE";
|
valueAxis.title.text = "Nilai SSE";
|
||||||
|
|
||||||
let lineSeries = chart.series.push(new am4charts.LineSeries());
|
let lineSeries = chart.series.push(new am4charts.LineSeries());
|
||||||
|
|
||||||
lineSeries.dataFields.valueY = "sse";
|
lineSeries.dataFields.valueY = "sse";
|
||||||
lineSeries.dataFields.categoryX = "k";
|
lineSeries.dataFields.categoryX = "k";
|
||||||
lineSeries.name = "SSE";
|
lineSeries.name = "SSE";
|
||||||
lineSeries.strokeWidth = 2;
|
lineSeries.strokeWidth = 2;
|
||||||
lineSeries.tooltipText = "K={categoryX}\nSSE={valueY}\nCentroid Awal: {centroid_awal}";
|
lineSeries.tooltipText = "K={categoryX}\nSSE={valueY}"; // Tooltip tanpa centroid_awal
|
||||||
lineSeries.tensionX = 1;
|
lineSeries.tensionX = 1;
|
||||||
|
|
||||||
let bullet = lineSeries.bullets.push(new am4charts.CircleBullet());
|
let bullet = lineSeries.bullets.push(new am4charts.CircleBullet());
|
||||||
|
@ -5236,20 +5235,19 @@ if (jQuery("#editor").length) {
|
||||||
fetch(`/storage/sse_elbow_${type}.json`)
|
fetch(`/storage/sse_elbow_${type}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
// Format data untuk chart
|
||||||
chart.data = data.map(item => ({
|
chart.data = data.map(item => ({
|
||||||
k: item.k,
|
k: item.k,
|
||||||
sse: item.sse,
|
sse: item.sse
|
||||||
centroid_awal: item.centroid_awal.join(", ")
|
|
||||||
}));
|
}));
|
||||||
console.log("Data yang dimuat ke chart:", chart.data);
|
console.log("Data yang dimuat ke chart:", chart.data);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load data default saat pertama kali (curas)
|
// Load data default saat pertama kali (curanmor)
|
||||||
loadChartData('curanmor');
|
loadChartData('curanmor');
|
||||||
|
|
||||||
// Event listener dropdown
|
// Event listener dropdown untuk memilih tipe data
|
||||||
document.querySelectorAll('.chart-option').forEach(item => {
|
document.querySelectorAll('.chart-option').forEach(item => {
|
||||||
item.addEventListener('click', function(e) {
|
item.addEventListener('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
</div>
|
</div>
|
||||||
<a href="/dashboard/curas/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Kasus Curas</a>
|
<a href="/dashboard/curas/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Kasus Curas</a>
|
||||||
</div>
|
</div>
|
||||||
@if (session()->has('succes'))
|
</div>
|
||||||
|
@if (session()->has('succes'))
|
||||||
<div class="alert alert-success" role="alert">
|
<div class="alert alert-success" role="alert">
|
||||||
{{ session('succes') }}
|
{{ session('succes') }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +22,7 @@
|
||||||
{{ session('error') }}
|
{{ session('error') }}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="table-responsive rounded mb-3">
|
<div class="table-responsive rounded mb-3">
|
||||||
<table class="data-table table mb-0 tbl-server-info">
|
<table class="data-table table mb-0 tbl-server-info">
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>No</th>
|
<th>No</th>
|
||||||
<th>Nama Kecamatan</th>
|
<th class="text-center">Nama Kecamatan</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>{{ $kecamatan -> id }}</td>
|
<td>{{ $kecamatan -> id }}</td>
|
||||||
<td>{{ $kecamatan -> nama_kecamatan }}</td>
|
<td>{{ $kecamatan -> nama_kecamatan }}</td>
|
||||||
<td>
|
<td class="text-center">
|
||||||
<div class="d-flex align-items-center list-action">
|
<div class="d-flex align-items-center list-action">
|
||||||
<a class="badge bg-success mr-2" data-toggle="tooltip" data-placement="top" title=""
|
<a class="badge bg-success mr-2" data-toggle="tooltip" data-placement="top" title=""
|
||||||
href="/dashboard/kecamatan/{{ $kecamatan ->id}}/edit"><i class="ri-pencil-line mr-0"></i></a>
|
href="/dashboard/kecamatan/{{ $kecamatan ->id}}/edit"><i class="ri-pencil-line mr-0"></i></a>
|
||||||
|
|
|
@ -13,15 +13,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (session()->has('succes'))
|
@if (session()->has('succes'))
|
||||||
<div class="alert alert-success" role="alert">
|
<div class="alert alert-success" role="alert">
|
||||||
{{ session('succes') }}
|
{{ session('succes') }}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (session()->has('error'))
|
@if (session()->has('error'))
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
{{ session('error') }}
|
{{ session('error') }}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="table-responsive rounded mb-3">
|
<div class="table-responsive rounded mb-3">
|
||||||
<table class="data-table table mb-0 tbl-server-info">
|
<table class="data-table table mb-0 tbl-server-info">
|
||||||
|
|
|
@ -357,12 +357,11 @@ class="rounded profile-img img-fluid avatar-70">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<ul class="list-inline mb-0">
|
<ul class="list-inline mb-0">
|
||||||
<li class="list-inline-item"><a href="../backend/privacy-policy.html">Privacy Policy</a></li>
|
<li class="list-inline-item">Designed By : <a target="blank" href="https://iqonic.design/">Iconic.Design</a></li>
|
||||||
<li class="list-inline-item"><a href="../backend/terms-of-service.html">Terms of Use</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 text-right">
|
<div class="col-lg-6 text-right">
|
||||||
<span class="mr-1"><script>document.write(new Date().getFullYear())</script>©</span> <a href="#" class="">POS Dash</a>.
|
<span class="mr-1"><script>document.write(new Date().getFullYear())</script>©</span> <a href="/" class="">KProtect</a>.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue