445 lines
14 KiB
PHP
445 lines
14 KiB
PHP
<?php
|
|
defined('BASEPATH') or exit('No direct script access allowed');
|
|
|
|
require_once dirname(__FILE__) . "/../../metode/ExponentialSmoothing.php";
|
|
|
|
class Peramalan extends CI_Controller
|
|
{
|
|
|
|
function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->load->helper('url');
|
|
$this->load->model('M_pelayanan');
|
|
$this->load->model('M_pengunjung');
|
|
|
|
if ($this->session->userdata('status') != "login") {
|
|
redirect(base_url("Auth"));
|
|
}
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$id_pelayanan = $this->input->get('id_pelayanan');
|
|
$bulan = $this->input->get('bulan');
|
|
$tahun = $this->input->get('tahun');
|
|
$data['pelayanan'] = $this->M_pelayanan->get_all()->result();
|
|
$data['alpha'] = $this->M_pelayanan->alpha()->row_array();
|
|
|
|
if ($bulan != "" && $tahun != "") {
|
|
$data['detail_pelayanan'] = $this->M_pelayanan->get_detail($id_pelayanan)->row_array();
|
|
$ft = $this->get_peramalan($id_pelayanan, $bulan, $tahun);
|
|
$data['data'] = $ft['hasilRamal'];
|
|
$data['MAD'] = $ft['MAD'];
|
|
$data['MSE'] = $ft['MSE'];
|
|
$data['MAPE'] = $ft['MAPE'];
|
|
$data['ratarataKesalahan'] = $ft['ratarataKesalahan'];
|
|
} else {
|
|
$data['detail_pelayanan'] = null;
|
|
$data['data'] = [];
|
|
$data['MAD'] = null;
|
|
$data['MSE'] = null;
|
|
$data['MAPE'] = null;
|
|
$data['ratarataKesalahan'] = null;
|
|
}
|
|
|
|
$this->load->view('peramalan', $data);
|
|
}
|
|
|
|
public function update_alpha()
|
|
{
|
|
$alpha = $this->input->post('alpha');
|
|
$beta = $this->input->post('beta');
|
|
$gamma = $this->input->post('gamma');
|
|
$data = array(
|
|
'alpha' => $alpha,
|
|
'beta' => $beta,
|
|
'gamma' => $gamma
|
|
);
|
|
|
|
$where = array(
|
|
'id_alpha' => '1'
|
|
);
|
|
$this->M_pelayanan->update($where, $data, 'alpha');
|
|
|
|
$response['success'] = true;
|
|
$response['message'] = "Alpha Berhasil Diubah !";
|
|
echo json_encode($response);
|
|
}
|
|
|
|
public function get_peramalan($id_pelayanan, $bulan, $tahun)
|
|
{
|
|
$hasilRamal = array();
|
|
$awal = $this->M_pengunjung->tgl_kunjungan($id_pelayanan, 'asc')->row_array();
|
|
$akhir = $this->M_pengunjung->tgl_kunjungan($id_pelayanan, 'desc')->row_array();
|
|
|
|
$params = $this->M_pelayanan->alpha()->row_array();
|
|
$alpha = $params['alpha'];
|
|
$beta = $params['beta'];
|
|
$gamma = $params['gamma'];
|
|
$L = $params['periode'];
|
|
|
|
$dataAktual = [];
|
|
$blnRamal = $tahun . '-' . $bulan . '-01';
|
|
$blnAwal = isset($awal['tanggal']) ? $awal['tanggal'] : date('Y-m-d');
|
|
$blnAkhir = isset($akhir['tanggal']) ? $akhir['tanggal'] : date('Y-m-d');
|
|
|
|
// mengambil data rekap pengunjung
|
|
if ($id_pelayanan!="") {
|
|
$srs = $this->M_pengunjung->get_rekap_pengunjung($id_pelayanan)->result_array();
|
|
} else {
|
|
$srs = $this->M_pengunjung->get_rekap_total_pengunjung()->result_array();
|
|
}
|
|
|
|
// Mengambil nilai data aktual
|
|
foreach ($srs as $row) {
|
|
$dataAktual[] = $row['jumlah'];
|
|
}
|
|
|
|
$starter = 0;
|
|
$lb = 0;
|
|
// generate list bulan dan jumlah data aktual, dari awal hingga akhir bulan kunjungan pada setiap pelayanan
|
|
for ($t = date("Y", strtotime($blnAkhir)); $t <= date("Y", strtotime($blnRamal)); $t++) {
|
|
if ($starter == 0) {
|
|
$lb = date("m", strtotime($blnAkhir)) + 1;
|
|
} else {
|
|
$lb = 1;
|
|
}
|
|
|
|
for ($b = $lb; $b <= 13; $b++) {
|
|
if ($b > 12) {
|
|
$starter = 1;
|
|
break;
|
|
} else {
|
|
|
|
if ($t == date("Y", strtotime($blnRamal)) && $b > date("m", strtotime($blnRamal))) {
|
|
break;
|
|
} else {
|
|
// proses menambahkan / menggabungkan data series bulanan dengan bulan selanjutnya
|
|
$bulanStr = sprintf("%02d", $b) . "-" . $t;
|
|
$srs[] = array(
|
|
'bulan' => $bulanStr,
|
|
'jumlah' => null
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Jika data rekap pengunjung sebelumnya kosong maka akan mengembalikan nilai dengan data peramalan null
|
|
if (count($dataAktual) == 0) {
|
|
for ($i = 0; $i < count($srs); $i++) {
|
|
$hasilRamal[] = array(
|
|
'bulan' => $srs[$i]['bulan'],
|
|
'jumlah' => isset($srs[$i]['jumlah']) ? $srs[$i]['jumlah'] : 0,
|
|
'lt' => null,
|
|
'bt' => null,
|
|
'st' => null,
|
|
'ft' => null,
|
|
'xt_ft' => null,
|
|
'xt_ft2' => null,
|
|
'error' => null,
|
|
);
|
|
}
|
|
|
|
$result['hasilRamal'] = $hasilRamal;
|
|
$result['MAD'] = null;
|
|
$result['MSE'] = null;
|
|
$result['MAPE'] = null;
|
|
$result['ratarataKesalahan'] = null;
|
|
|
|
return $result;
|
|
}
|
|
|
|
// Fungsi metode triple exponential smoothing
|
|
$h = new ExponentialSmoothing($alpha, $beta, $gamma, $L, $dataAktual);
|
|
$dataForecast = $h->get_forecast();
|
|
|
|
// Perhitungan error
|
|
// rumus PE : ABS(xt-ft/xt)x100
|
|
$arrPE = array();
|
|
$arrPE2 = array();
|
|
$PE = array();
|
|
$MAD = 0;
|
|
$MSE = 0;
|
|
$MAPE = 0;
|
|
for ($i = 0; $i < count($dataForecast); $i++) {
|
|
if (isset($dataForecast[$i])) {
|
|
// | xt-ft |
|
|
$xtFt = $dataAktual[$i] - $dataForecast[$i];
|
|
$arrPE[] = ABS($xtFt);
|
|
// (xt-ft)^2
|
|
$xtFt2 = pow($xtFt, 2);
|
|
$arrPE2[] = $xtFt2;
|
|
// ABS(xt-ft/xt)x100
|
|
$APE = ABS($xtFt / $dataAktual[$i]) * 100;
|
|
$PE[] = $APE;
|
|
// Total
|
|
$MAD += ABS($xtFt);
|
|
$MSE += $xtFt2;
|
|
$MAPE += $APE;
|
|
} else {
|
|
$arrPE[] = null;
|
|
$arrPE2[] = null;
|
|
$PE[] = null;
|
|
}
|
|
};
|
|
|
|
$jmlAktual = count($dataForecast) - $L;
|
|
$hasilMAD = $MAD / $jmlAktual;
|
|
$hasilMSE = $MSE / $jmlAktual;
|
|
$hasilMAPE = $MAPE / $jmlAktual;
|
|
$hasilKeseluruhan = $hasilMAD + $hasilMSE + $hasilMAPE;
|
|
$ratarataKesalahan = $hasilKeseluruhan / 3;
|
|
|
|
// proses merge data ramal aktual dengan bulan selanjutnya
|
|
for ($i = count($dataAktual); $i < count($srs); $i++) {
|
|
$dataForecast[] = $h->forecast($i);
|
|
}
|
|
|
|
// Peramalan
|
|
$levels = $h->get_levels();
|
|
$trens = $h->get_trens();
|
|
$seasonals = $h->get_seasonals();
|
|
for ($i = 0; $i < count($srs); $i++) {
|
|
$hasilRamal[] = array(
|
|
'bulan' => $srs[$i]['bulan'],
|
|
'jumlah' => $srs[$i]['jumlah'],
|
|
'lt' => (isset($levels[$i])) ? round($levels[$i], 5) : null,
|
|
'bt' => (isset($trens[$i])) ? round($trens[$i], 5) : null,
|
|
'st' => (isset($seasonals[$i])) ? round($seasonals[$i], 5) : null,
|
|
'ft' => (isset($dataForecast[$i])) ? round($dataForecast[$i], 5) : null,
|
|
'xt_ft' => (isset($arrPE[$i])) ? round($arrPE[$i], 5) : null,
|
|
'xt_ft2' => (isset($arrPE2[$i])) ? round($arrPE2[$i], 5) : null,
|
|
'error' => (isset($PE[$i])) ? round($PE[$i], 5) : null,
|
|
);
|
|
}
|
|
|
|
$result['hasilRamal'] = $hasilRamal;
|
|
$result['MAD'] = round($hasilMAD, 4);
|
|
$result['MSE'] = round($hasilMSE, 4);
|
|
$result['MAPE'] = round($hasilMAPE, 4);
|
|
$result['ratarataKesalahan'] = round($ratarataKesalahan, 4);
|
|
|
|
return $result;
|
|
}
|
|
|
|
// Fungsi untuk testing perhitungan development
|
|
public function forecast()
|
|
{
|
|
|
|
$starter = 0;
|
|
$lb = 0;
|
|
|
|
$dataAktual = [];
|
|
$blnAwal = '2023-04-01';
|
|
$blnAkhir = '2024-03-01';
|
|
$blnRamal = '2024-05-01';
|
|
|
|
$srs = array(
|
|
array(
|
|
'bulan' => '04-2023',
|
|
'jumlah' => 32
|
|
),
|
|
array(
|
|
'bulan' => '05-2023',
|
|
'jumlah' => 32
|
|
),
|
|
array(
|
|
'bulan' => '06-2023',
|
|
'jumlah' => 33
|
|
),
|
|
array(
|
|
'bulan' => '07-2023',
|
|
'jumlah' => 35
|
|
),
|
|
array(
|
|
'bulan' => '08-2023',
|
|
'jumlah' => 38
|
|
),
|
|
array(
|
|
'bulan' => '09-2023',
|
|
'jumlah' => 36
|
|
),
|
|
array(
|
|
'bulan' => '10-2023',
|
|
'jumlah' => 36
|
|
),
|
|
array(
|
|
'bulan' => '11-2023',
|
|
'jumlah' => 32
|
|
),
|
|
array(
|
|
'bulan' => '12-2023',
|
|
'jumlah' => 33
|
|
),
|
|
array(
|
|
'bulan' => '01-2024',
|
|
'jumlah' => 31
|
|
),
|
|
array(
|
|
'bulan' => '02-2024',
|
|
'jumlah' => 33
|
|
),
|
|
array(
|
|
'bulan' => '03-2024',
|
|
'jumlah' => 34
|
|
),
|
|
);
|
|
|
|
// Mengambil nilai data aktual
|
|
foreach ($srs as $row) {
|
|
$dataAktual[] = $row['jumlah'];
|
|
}
|
|
|
|
// generate list bulan dan jumlah data aktual, dari awal hingga akhir bulan kunjungan pada setiap pelayanan
|
|
for ($t = date("Y", strtotime($blnAkhir)); $t <= date("Y", strtotime($blnRamal)); $t++) {
|
|
if ($starter == 0) {
|
|
$lb = date("m", strtotime($blnAkhir)) + 1;
|
|
} else {
|
|
$lb = 1;
|
|
}
|
|
|
|
for ($b = $lb; $b <= 13; $b++) {
|
|
if ($b > 12) {
|
|
$starter = 1;
|
|
break;
|
|
} else {
|
|
|
|
if ($t == date("Y", strtotime($blnRamal)) && $b > date("m", strtotime($blnRamal))) {
|
|
break;
|
|
} else {
|
|
// proses menambahkan / menggabungkan data series bulanan dengan bulan selanjutnya
|
|
$bulanStr = sprintf("%02d", $b) . "-" . $t;
|
|
$srs[] = array(
|
|
'bulan' => $bulanStr,
|
|
'jumlah' => null
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$alpha = 0.5;
|
|
$beta = 0.5;
|
|
$gamma = 0.5;
|
|
$L = 4;
|
|
|
|
// $series = array(
|
|
// 32,
|
|
// 32,
|
|
// 33,
|
|
// 35,
|
|
// 38,
|
|
// 36,
|
|
// 36,
|
|
// 32,
|
|
// 33,
|
|
// 31,
|
|
// 33,
|
|
// 34
|
|
// );
|
|
|
|
// Fungsi metode triple exponential smoothing
|
|
$h = new ExponentialSmoothing($alpha, $beta, $gamma, $L, $dataAktual);
|
|
$dataForecast = $h->get_forecast();
|
|
|
|
echo '<pre>';
|
|
// print_r($srs);
|
|
print_r($dataAktual);
|
|
// print_r($h);
|
|
echo '<br> Result forecast ori : <br>';
|
|
print_r($dataForecast);
|
|
echo '<br> Result forecast future : <br>';
|
|
|
|
// Perhitungan error
|
|
// rumus PE : ABS(xt-ft/xt)x100
|
|
|
|
$arrPE = array();
|
|
$arrPE2 = array();
|
|
$PE = array();
|
|
$MAD = 0;
|
|
$MSE = 0;
|
|
$MAPE = 0;
|
|
for ($i = 0; $i < count($dataForecast); $i++) {
|
|
if (isset($dataForecast[$i])) {
|
|
// | xt-ft |
|
|
$xtFt = $dataAktual[$i] - $dataForecast[$i];
|
|
$arrPE[] = ABS($xtFt);
|
|
// (xt-ft)^2
|
|
$xtFt2 = pow($xtFt, 2);
|
|
$arrPE2[] = $xtFt2;
|
|
// ABS(xt-ft/xt)x100
|
|
$APE = ABS($xtFt / $dataAktual[$i]) * 100;
|
|
$PE[] = $APE;
|
|
// Total
|
|
$MAD += ABS($xtFt);
|
|
$MSE += $xtFt2;
|
|
$MAPE += $APE;
|
|
} else {
|
|
$arrPE[] = null;
|
|
$arrPE2[] = null;
|
|
$PE[] = null;
|
|
}
|
|
};
|
|
|
|
$jmlAktual = count($dataForecast) - $L;
|
|
echo '<br> xt-ft : <br>';
|
|
print_r($arrPE);
|
|
print_r($arrPE2);
|
|
print_r($PE);
|
|
echo '<br>SUM MAD :';
|
|
print_r($MAD);
|
|
echo '<br>SUM MSE :';
|
|
print_r($MSE);
|
|
echo '<br>SUM PE :';
|
|
print_r($MAPE);
|
|
echo '<br>JML DATA AKTUAL :';
|
|
print_r($jmlAktual);
|
|
|
|
$hasilMAD = $MAD / $jmlAktual;
|
|
$hasilMSE = $MSE / $jmlAktual;
|
|
$hasilMAPE = $MAPE / $jmlAktual;
|
|
|
|
echo '<br>MAD :';
|
|
print_r($hasilMAD);
|
|
echo '<br>MSE :';
|
|
print_r($hasilMSE);
|
|
echo '<br>MAPE :';
|
|
print_r($hasilMAPE);
|
|
echo '<br>';
|
|
|
|
// proses merge data ramal aktual dengan bulan selanjutnya
|
|
for ($i = count($dataAktual); $i < count($srs); $i++) {
|
|
echo '[' . $i . '] ' . $h->forecast($i);
|
|
echo '<br>';
|
|
$dataForecast[] = $h->forecast($i);
|
|
}
|
|
print_r($dataForecast);
|
|
|
|
// Peramalan
|
|
$hasilRamal = array();
|
|
$levels = $h->get_levels();
|
|
$trens = $h->get_trens();
|
|
$seasonals = $h->get_seasonals();
|
|
for ($i = 0; $i < count($srs); $i++) {
|
|
$hasilRamal[] = array(
|
|
'bulan' => $srs[$i]['bulan'],
|
|
'jumlah' => $srs[$i]['jumlah'],
|
|
'lt' => (isset($levels[$i])) ? $levels[$i] : null,
|
|
'bt' => (isset($trens[$i])) ? $trens[$i] : null,
|
|
'st' => (isset($seasonals[$i])) ? $seasonals[$i] : null,
|
|
'ft' => $dataForecast[$i],
|
|
'xt_ft' => (isset($arrPE[$i])) ? $arrPE[$i] : null,
|
|
'xt_ft2' => (isset($arrPE2[$i])) ? $arrPE2[$i] : null,
|
|
'error' => (isset($PE[$i])) ? $PE[$i] : null,
|
|
);
|
|
}
|
|
|
|
print_r($hasilRamal);
|
|
echo '</pre>';
|
|
|
|
return $hasilRamal;
|
|
}
|
|
}
|