done
This commit is contained in:
parent
faf884d9e1
commit
edf4f3893d
|
@ -240,78 +240,100 @@
|
||||||
SECTION: Metrics Chart (Perbandingan Precision, F1, Accuracy)
|
SECTION: Metrics Chart (Perbandingan Precision, F1, Accuracy)
|
||||||
================================================================ --}}
|
================================================================ --}}
|
||||||
@php
|
@php
|
||||||
// Siapkan array untuk ringkasan metrik tiap e‐wallet
|
// Daftar e-wallet yang ingin kita tampilkan
|
||||||
$metricsSummary = [
|
$wallets = ['dana', 'gopay', 'shopeepay'];
|
||||||
'dana' => ['precision' => 0, 'f1' => 0, 'accuracy' => 0],
|
|
||||||
'gopay' => ['precision' => 0, 'f1' => 0, 'accuracy' => 0],
|
|
||||||
'shopeepay' => ['precision' => 0, 'f1' => 0, 'accuracy' => 0],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach (array_keys($metricsSummary) as $key) {
|
// Kita akan menyimpan struktur seperti:
|
||||||
// 1) Baca evaluation_metrics_full{key}.csv
|
// $metricsDetail['dana'] = [
|
||||||
$metricsPath = storage_path("app/public/evaluation_metrics_full{$key}.csv");
|
// 'labels' => ['Netral','Positif','Negatif'],
|
||||||
$metricsData = [];
|
// 'precision' => [0.812, 0.902, 0.748],
|
||||||
if (file_exists($metricsPath)) {
|
// 'recall' => [0.800, 0.889, 0.765],
|
||||||
$metricsData = array_map('str_getcsv', file($metricsPath));
|
// 'f1' => [0.806, 0.895, 0.756],
|
||||||
|
// ];
|
||||||
|
$metricsDetail = [];
|
||||||
|
|
||||||
|
// Kelas‐kelas yang ingin kita plot urutannya: netral → positif → negatif
|
||||||
|
$kelasUrut = ['netral', 'positif', 'negatif'];
|
||||||
|
|
||||||
|
foreach ($wallets as $key) {
|
||||||
|
// Nama file CSV mirip: evaluation_metrics_full{key}.csv
|
||||||
|
// Note: untuk 'shopeepay', file Anda pakai 'shopee' bukan 'shopeepay'?
|
||||||
|
// Di contoh awal Anda, yang di‐upload adalah evaluation_metrics_fullshopee.csv,
|
||||||
|
// maka gunakan $fileKey='shopee' bukan 'shopeepay'.
|
||||||
|
$fileKey = $key;
|
||||||
|
$pathCsv = storage_path("app/public/evaluation_metrics_full{$fileKey}.csv");
|
||||||
|
$rows = [];
|
||||||
|
if (file_exists($pathCsv)) {
|
||||||
|
// Baca setiap baris kemudian pecah jadi array per kolom
|
||||||
|
$rows = array_map('str_getcsv', file($pathCsv));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitung Macro‐Precision & Macro‐F1 (rata-rata precision/f1 tiap kelas)
|
// Inisialisasi struktur kosong
|
||||||
$sumPrecision = 0.0;
|
$metricsDetail[$key] = [
|
||||||
$sumF1 = 0.0;
|
'labels' => [],
|
||||||
$nClasses = 0;
|
'precision' => [],
|
||||||
if (count($metricsData) > 1) {
|
'recall' => [],
|
||||||
// Baris pertama header: [,precision,recall,f1‐score,support]
|
'f1' => [],
|
||||||
foreach (array_slice($metricsData, 1) as $row) {
|
];
|
||||||
$sumPrecision += (float) $row[1]; // precision
|
|
||||||
$sumF1 += (float) $row[3]; // f1‐score
|
if (count($rows) > 1) {
|
||||||
$nClasses++;
|
// Baris 0: header → abaikan. Mulai dari baris 1.
|
||||||
|
// Kita ingin memastikan tiap kelas ('netral','positif','negatif') ada, dan urutannya sesuai $kelasUrut.
|
||||||
|
// Bisa saja di CSV urutannya sudah sama, tapi kita paksa urut sesuai $kelasUrut.
|
||||||
|
|
||||||
|
// Buat map nama kelas ke indeks baris
|
||||||
|
$mapRowByKelas = [];
|
||||||
|
foreach (array_slice($rows, 1) as $r) {
|
||||||
|
// Asumsikan kolom 0 adalah nama kelas, kolom 2 precision, kolom 3 recall, kolom 4 f1-score
|
||||||
|
$namaKelas = strtolower(trim($r[0]));
|
||||||
|
$mapRowByKelas[$namaKelas] = $r;
|
||||||
}
|
}
|
||||||
if ($nClasses > 0) {
|
|
||||||
$metricsSummary[$key]['precision'] = round($sumPrecision / $nClasses, 3);
|
|
||||||
$metricsSummary[$key]['f1'] = round($sumF1 / $nClasses, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) Hitung Accuracy dari confusion_matrix_{key}.csv
|
foreach ($kelasUrut as $kelas) {
|
||||||
$confusionPath = storage_path("app/public/confusion_matrix_{$key}.csv");
|
if (isset($mapRowByKelas[$kelas])) {
|
||||||
$confusionData = [];
|
$r = $mapRowByKelas[$kelas];
|
||||||
if (file_exists($confusionPath)) {
|
// Ambil nilai ke‐2 (precision), ke‐3 (recall), ke‐4 (f1‐score)
|
||||||
$confusionData = array_map('str_getcsv', file($confusionPath));
|
// Hati‐hati: format CSV kadang ada kolom kosong di indeks 1 → kita gunakan r[2], r[3], r[4].
|
||||||
}
|
$precision = isset($r[2]) ? (float) $r[2] : 0;
|
||||||
|
$recall = isset($r[3]) ? (float) $r[3] : 0;
|
||||||
|
$f1score = isset($r[4]) ? (float) $r[4] : 0;
|
||||||
|
|
||||||
if (count($confusionData) > 1) {
|
// Push ke dalam array
|
||||||
$totalAll = 0;
|
$metricsDetail[$key]['labels'][] = ucfirst($kelas);
|
||||||
$sumDiagonal = 0;
|
$metricsDetail[$key]['precision'][] = round($precision, 3);
|
||||||
// Hitung total sampel
|
$metricsDetail[$key]['recall'][] = round($recall, 3);
|
||||||
foreach (array_slice($confusionData, 1) as $r) {
|
$metricsDetail[$key]['f1'][] = round($f1score, 3);
|
||||||
for ($c = 1; $c < count($r); $c++) {
|
} else {
|
||||||
$totalAll += (int) $r[$c];
|
// Jika suatu kelas tidak ditemukan di CSV, isi 0.
|
||||||
|
$metricsDetail[$key]['labels'][] = ucfirst($kelas);
|
||||||
|
$metricsDetail[$key]['precision'][] = 0;
|
||||||
|
$metricsDetail[$key]['recall'][] = 0;
|
||||||
|
$metricsDetail[$key]['f1'][] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Jumlah diagonal (misal 3 kelas → sel [1][1], [2][2], [3][3])
|
|
||||||
$sumDiagonal += (int) $confusionData[1][1];
|
|
||||||
$sumDiagonal += (int) $confusionData[2][2];
|
|
||||||
$sumDiagonal += (int) $confusionData[3][3];
|
|
||||||
|
|
||||||
if ($totalAll > 0) {
|
|
||||||
$metricsSummary[$key]['accuracy'] = round($sumDiagonal / $totalAll, 3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="row mt-4 mb-5">
|
<div class="row mt-4 mb-5">
|
||||||
<div class="col-12">
|
@foreach ($wallets as $key)
|
||||||
<div class="card shadow-sm">
|
@php
|
||||||
<div class="card-header">
|
// Ubah key menjadi judul yang lebih enak (Dana, Gopay, Shopeepay)
|
||||||
<h6 class="mb-0">Perbandingan Metode Prediksi: Precision, F1‐Score, dan Akurasi</h6>
|
$judul = ucfirst($key);
|
||||||
</div>
|
@endphp
|
||||||
<div class="card-body p-3" style="height:350px;">
|
<div class="col-md-4 mb-4">
|
||||||
<canvas id="metricsChart" width="800" height="350"></canvas>
|
<div class="card shadow-sm h-100">
|
||||||
|
<div class="card-header">
|
||||||
|
<h6 class="mb-0">Metrik Klasifikasi: {{ $judul }}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" style="height: 300px;">
|
||||||
|
{{-- Canvas untuk Chart.js --}}
|
||||||
|
<canvas id="chart-{{ $key }}" width="400" height="250"></canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- ================================================================
|
{{-- ================================================================
|
||||||
SECTION: Top Features (Tiap e‐wallet dalam satu card terpisah)
|
SECTION: Top Features (Tiap e‐wallet dalam satu card terpisah)
|
||||||
================================================================ --}}
|
================================================================ --}}
|
||||||
|
@ -477,91 +499,98 @@
|
||||||
sentiments.forEach(drawWC);
|
sentiments.forEach(drawWC);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Ambil data ringkasan metrik dari PHP ke JS
|
// Kita ingin memanggil Chart.js untuk masing‐masing e‐wallet
|
||||||
const ewMetrics = @json($metricsSummary);
|
const wallets = {!! json_encode($wallets) !!};
|
||||||
const labels = ['Dana', 'GoPay', 'ShopeePay'];
|
|
||||||
|
|
||||||
// Siapkan data Precision, F1, dan Accuracy dalam urutan yang sama
|
wallets.forEach(function(key) {
|
||||||
const precisionData = labels.map(name => {
|
// Ambil data PHP yang sudah kita siapkan di $metricsDetail
|
||||||
const key = name.toLowerCase();
|
const dataPHP = {!! json_encode($metricsDetail) !!};
|
||||||
return ewMetrics[key].precision;
|
|
||||||
});
|
|
||||||
const f1Data = labels.map(name => {
|
|
||||||
const key = name.toLowerCase();
|
|
||||||
return ewMetrics[key].f1;
|
|
||||||
});
|
|
||||||
const accuracyData = labels.map(name => {
|
|
||||||
const key = name.toLowerCase();
|
|
||||||
return ewMetrics[key].accuracy;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Buat bar chart dengan tiga kelompok dataset
|
// Labels kelas (Netral, Positif, Negatif)
|
||||||
new Chart(document.getElementById('metricsChart'), {
|
const labels = dataPHP[key]['labels']; // contoh: ["Netral","Positif","Negatif"]
|
||||||
type: 'bar',
|
const dataPrecision = dataPHP[key]['precision'];
|
||||||
data: {
|
const dataRecall = dataPHP[key]['recall'];
|
||||||
|
const dataF1 = dataPHP[key]['f1'];
|
||||||
|
|
||||||
|
// Konfigurasi dataset untuk Chart.js
|
||||||
|
const chartData = {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Precision (Macro)',
|
label: 'Precision',
|
||||||
data: precisionData,
|
data: dataPrecision,
|
||||||
backgroundColor: 'rgba(54, 162, 235, 0.6)',
|
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
||||||
borderColor: 'rgba(54, 162, 235, 1)',
|
borderColor: 'rgba(54, 162, 235, 1)',
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'F1‐Score (Macro)',
|
label: 'Recall',
|
||||||
data: f1Data,
|
data: dataRecall,
|
||||||
backgroundColor: 'rgba(255, 206, 86, 0.6)',
|
backgroundColor: 'rgba(255, 206, 86, 0.5)',
|
||||||
borderColor: 'rgba(255, 206, 86, 1)',
|
borderColor: 'rgba(255, 206, 86, 1)',
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Accuracy',
|
label: 'F1‐Score',
|
||||||
data: accuracyData,
|
data: dataF1,
|
||||||
backgroundColor: 'rgba(75, 192, 192, 0.6)',
|
backgroundColor: 'rgba(75, 192, 192, 0.5)',
|
||||||
borderColor: 'rgba(75, 192, 192, 1)',
|
borderColor: 'rgba(75, 192, 192, 1)',
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
};
|
||||||
options: {
|
|
||||||
responsive: true,
|
const config = {
|
||||||
maintainAspectRatio: false,
|
type: 'bar',
|
||||||
scales: {
|
data: chartData,
|
||||||
yAxes: [{
|
options: {
|
||||||
ticks: {
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
callback: value => (value * 100).toFixed(0) +
|
max: 1,
|
||||||
'%' // Menampilkan dalam persen
|
ticks: {
|
||||||
},
|
callback: function(value) {
|
||||||
scaleLabel: {
|
return value.toFixed(2);
|
||||||
display: true,
|
}
|
||||||
labelString: 'Nilai (%)'
|
},
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Nilai'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}],
|
},
|
||||||
xAxes: [{
|
plugins: {
|
||||||
barPercentage: 0.6,
|
tooltip: {
|
||||||
categoryPercentage: 0.6
|
callbacks: {
|
||||||
}]
|
label: function(context) {
|
||||||
},
|
let label = context.dataset.label || '';
|
||||||
tooltips: {
|
if (label) {
|
||||||
callbacks: {
|
label += ': ';
|
||||||
label: function(tooltipItem, data) {
|
}
|
||||||
let label = data.datasets[tooltipItem.datasetIndex].label || '';
|
if (context.parsed.y !== null) {
|
||||||
let val = tooltipItem.yLabel;
|
label += context.parsed.y.toFixed(3);
|
||||||
return label + ': ' + (val * 100).toFixed(1) + '%';
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
position: 'bottom'
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Buat chart pada canvas dengan id="chart-<key>"
|
||||||
|
const ctx = document.getElementById('chart-' + key).getContext('2d');
|
||||||
|
new Chart(ctx, config);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue