distinct()->orderBy('tahun')->pluck('tahun'); // Jika tidak ada tahun yang dipilih, gunakan tahun pertama yang tersedia $selectedYear = $request->input('year', $availableYears->first()); // Ambil data jumlah kasus DBD dari database untuk tahun tertentu $dataByYear = DataDBD::where('tahun', $selectedYear)->get(); // Buat objek MonthlyDBDChart dengan memberikan data dan tahun yang dipilih $monthlyChart = new MonthlyDBDChart($dataByYear, $selectedYear); // Bangun chart untuk jumlah kasus DBD setiap bulannya $monthlyChartData = $monthlyChart->build(); // // Bangun chart untuk jumlah kasus DBD setiap tahunnya $yearlyChartData = $yearlyChart->build(); $clusterResults = Session::get('clusterResults'); // Kembalikan view dengan chart yang dibuat dan daftar tahun yang tersedia return view('dashboard', [ 'clusterResults' => $clusterResults, 'monthlyChart' => $monthlyChartData, 'yearlyChart' => $yearlyChartData, 'selectedYear' => $selectedYear, 'availableYears' => $availableYears // Sertakan daftar tahun yang tersedia ]); } public function index() { // Mengambil data dari tabel DataDBD $data = DataDBD::all(); $kecamatanData = Kecamatan::all()->keyBy('id')->toArray(); // Menggabungkan jumlah kasus dan jumlah penduduk untuk kecamatan yang sama dari semua tahun $dataset = []; foreach ($data as $d) { $key = $d->id_kecamatan; if (!isset($dataset[$key])) { $dataset[$key] = [ 'id_kecamatan' => $d->id_kecamatan, 'nama_kecamatan' => $kecamatanData[$d->id_kecamatan]['nama_kecamatan'] ?? 'Unknown', 'latitude' => $kecamatanData[$d->id_kecamatan]['latitude'] ?? null, 'longitude' => $kecamatanData[$d->id_kecamatan]['longitude'] ?? null, 'jumlah_penduduk' => (int) $kecamatanData[$d->id_kecamatan]['jumlah_penduduk'], 'jumlah_kasus' => (int) $d->jumlah_kasus, 'cases_per_capita' => (int) $d->jumlah_kasus / max((int) $kecamatanData[$d->id_kecamatan]['jumlah_penduduk'], 1) // Prevent division by zero ]; } else { $dataset[$key]['jumlah_kasus'] += (int) $d->jumlah_kasus; $dataset[$key]['cases_per_capita'] = $dataset[$key]['jumlah_kasus'] / max((int) $dataset[$key]['jumlah_penduduk'], 1); // Prevent division by zero } } // Mengubah array asosiatif menjadi array numerik $dataset = array_values($dataset); // Menjalankan algoritma K-Means $k = 3; $result = $this->kMeans($dataset, $k); // Menghitung tingkat kasus berdasarkan perhitungan statistik $caseLevels = $this->calculateCaseLevels($dataset); // Mengelompokkan hasil clustering berdasarkan kecamatan $clusterResults = []; foreach ($result['clusters'] as $clusterIndex => $cluster) { foreach ($cluster as $datum) { $clusterResults[$datum['id_kecamatan']] = [ 'id_kecamatan' => $datum['id_kecamatan'], 'nama_kecamatan' => $datum['nama_kecamatan'], 'latitude' => $datum['latitude'], 'longitude' => $datum['longitude'], 'cluster' => $clusterIndex + 1, 'cases_per_capita' => $datum['cases_per_capita'], 'jumlah_penduduk' => $datum['jumlah_penduduk'], 'jumlah_kasus' => $datum['jumlah_kasus'], 'tingkat_kasus' => $caseLevels[$datum['id_kecamatan']] ]; } } Session::put('clusterResults', $clusterResults); // Menampilkan hasil perhitungan K-Means return view('kmeans.index', [ 'steps' => $result['steps'], 'clusterResults' => $clusterResults, 'kecamatanData' => $kecamatanData ]); } private function calculateCaseLevels($dataset) { $casesPerCapita = array_column($dataset, 'cases_per_capita'); $mean = array_sum($casesPerCapita) / count($casesPerCapita); $stdDev = sqrt(array_sum(array_map(fn($x) => pow($x - $mean, 2), $casesPerCapita)) / count($casesPerCapita)); $thresholdLow = $mean - $stdDev; $thresholdHigh = $mean + $stdDev; $caseLevels = []; foreach ($dataset as $data) { if ($data['cases_per_capita'] <= $thresholdLow) { $caseLevels[$data['id_kecamatan']] = 'Rendah'; } elseif ($data['cases_per_capita'] >= $thresholdHigh) { $caseLevels[$data['id_kecamatan']] = 'Tinggi'; } else { $caseLevels[$data['id_kecamatan']] = 'Sedang'; } } return $caseLevels; } private function kMeans($data, $k) { // Inisialisasi centroids secara acak $centroids = []; $usedKecamatanIds = []; // Array untuk menyimpan ID kecamatan yang sudah digunakan sebagai centroid for ($i = 0; $i < $k; $i++) { // Pilih kecamatan secara acak do { $randomIndex = array_rand($data); $randomKecamatanId = $data[$randomIndex]['id_kecamatan']; } while (in_array($randomKecamatanId, $usedKecamatanIds)); // Periksa apakah kecamatan sudah digunakan sebagai centroid sebelumnya // Tambahkan kecamatan ke array centroid dan array kecamatan yang sudah digunakan $centroids[$i] = $data[$randomIndex]; $usedKecamatanIds[] = $randomKecamatanId; } $iterations = 100; $steps = []; for ($i = 0; $i < $iterations; $i++) { $clusters = array_fill(0, $k, []); // Menempatkan setiap data ke klaster terdekat foreach ($data as $datum) { $distances = []; foreach ($centroids as $centroid) { $distances[] = $this->euclideanDistance($datum, $centroid); } $cluster = array_keys($distances, min($distances))[0]; $clusters[$cluster][] = $datum; } // Menyimpan langkah perhitungan $steps[] = [ 'iteration' => $i + 1, 'centroids' => $centroids, 'clusters' => $clusters ]; // Menghitung centroid baru $newCentroids = []; foreach ($clusters as $cluster => $clusterData) { $newCentroids[$cluster] = $this->calculateCentroid($clusterData); } // Memeriksa konvergensi if ($this->centroidsConverged($centroids, $newCentroids)) { break; } // Memperbarui centroid untuk iterasi berikutnya $centroids = $newCentroids; } return ['clusters' => $clusters, 'steps' => $steps]; } private function euclideanDistance($datum1, $datum2) { return sqrt( pow($datum1['jumlah_penduduk'] - $datum2['jumlah_penduduk'], 2) + pow($datum1['jumlah_kasus'] - $datum2['jumlah_kasus'], 2) ); } private function calculateCentroid($clusterData) { $centroid = [ 'id_kecamatan' => null, 'nama_kecamatan' => '', 'jumlah_penduduk' => 0, 'jumlah_kasus' => 0 ]; $count = count($clusterData); // Pastikan jumlah data tidak nol sebelum melakukan pembagian if ($count > 0) { foreach ($clusterData as $data) { $centroid['jumlah_penduduk'] += (int) $data['jumlah_penduduk']; $centroid['jumlah_kasus'] += (int) $data['jumlah_kasus']; } $centroid['jumlah_penduduk'] /= $count; $centroid['jumlah_kasus'] /= $count; // Mengatur id_kecamatan dari salah satu data terdekat ke centroid baru $closestDatum = $this->getClosestDatum($centroid, $clusterData); $centroid['id_kecamatan'] = $closestDatum['id_kecamatan']; $centroid['nama_kecamatan'] = $closestDatum['nama_kecamatan']; } return $centroid; } private function getClosestDatum($centroid, $clusterData) { $minDistance = PHP_FLOAT_MAX; $closestDatum = null; foreach ($clusterData as $datum) { $distance = $this->euclideanDistance($centroid, $datum); if ($distance < $minDistance) { $minDistance = $distance; $closestDatum = $datum; } } return $closestDatum; } private function centroidsConverged($centroids, $newCentroids) { foreach ($centroids as $key => $centroid) { if ($this->euclideanDistance($centroid, $newCentroids[$key]) > 0.0001) { return false; } } return true; } }