BTA_Prediction / bta_xgboost.py
Rendhaputra's picture
Integrasi model Prophet dan tombol selektor interaktif di dashboard
89065dc
# -*- coding: utf-8 -*-
"""XGBOOST.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1tDtwG0rHNfmKvSU-iQ32jGa1xB4HAqCn
"""
# -*- coding: utf-8 -*-
"""
BTA_Predict_FINAL.ipynb
================================================
BTA Thickness Prediction — Production-Ready Version
Strategy: Anchor-Based Wear Rate Model
(didasarkan insight bahwa:
- Ketebalan diukur manual → diskrit, bukan harian
- Korelasi waktu vs ketebalan = -0.995
- Korelasi suhu vs ketebalan = -0.16 (lemah)
→ Prediksi = Anchor terakhir + laju aus + suhu modifier)
================================================
"""
# ============================================================
# CELL 1: Install & Import
# ============================================================
# !pip install -q xgboost scikit-learn pandas numpy matplotlib seaborn
import pandas as pd
import numpy as np
from xgboost import XGBRegressor
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_absolute_error, mean_squared_error
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn as sns
import warnings, io
warnings.filterwarnings('ignore')
print("✅ Libraries loaded.")
# ============================================================
# CELL 2: Upload & Load Data
# ============================================================
import os
import sys
import glob
# Cari semua berkas CSV di folder saat ini
csv_files = glob.glob('*.csv') + glob.glob('*.csv.csv')
# Hilangkan duplikat dan rapikan path
csv_files = list(set([os.path.basename(f) for f in csv_files]))
# Prioritaskan argumen baris perintah
if len(sys.argv) > 1:
filename = sys.argv[1]
if not os.path.exists(filename):
print(f"❌ File '{filename}' yang diberikan melalui argumen tidak ditemukan!")
sys.exit(1)
else:
# Jika tidak ada argumen, cari CSV secara otomatis
if not csv_files:
raise FileNotFoundError("Tidak ditemukan file CSV di direktori saat ini.")
elif len(csv_files) == 1:
filename = csv_files[0]
else:
print("\n📂 Ditemukan beberapa file CSV di direktori saat ini:")
for idx, f in enumerate(csv_files, 1):
print(f" [{idx}] {f}")
# Cari default file jika ada
default_file = 'data-temp-clean.csv'
if default_file not in csv_files and 'data-temp-clean.csv.csv' in csv_files:
default_file = 'data-temp-clean.csv.csv'
default_idx = csv_files.index(default_file) + 1 if default_file in csv_files else 1
try:
choice = input(f"Pilih file untuk diproses (Tekan Enter untuk default [{csv_files[default_idx-1]}]): ").strip()
if choice == "":
filename = csv_files[default_idx-1]
else:
choice_idx = int(choice) - 1
if 0 <= choice_idx < len(csv_files):
filename = csv_files[choice_idx]
else:
print("❌ Pilihan tidak valid. Menggunakan file default.")
filename = csv_files[default_idx-1]
except Exception:
filename = csv_files[default_idx-1]
print(f"📂 Membaca file data: '{filename}'")
df = pd.read_csv(filename)
# Menentukan nama dasar berkas untuk keluaran dinamis
base_name = os.path.splitext(filename)[0]
if base_name.endswith('.csv'):
base_name = os.path.splitext(base_name)[0]
# bersihin nama kolom dari spasi
df.columns = [str(c).strip() for c in df.columns]
# rename kolomnya biar gampang dipanggil
df = df.rename(columns={
'Tanggal' : 'tanggal',
'Cone Depan (°C)' : 'cone_depan',
'Bodi Tengah (°C)' : 'body_tengah',
'Cone Belakang (°C)': 'cone_belakang',
'Ketebalan BTA (mm)': 'ketebalan'
})
# pastiin tipe data udah angka
for col in ['cone_depan', 'body_tengah', 'cone_belakang', 'ketebalan']:
df[col] = pd.to_numeric(df[col], errors='coerce')
df['tanggal'] = pd.to_datetime(df['tanggal'], dayfirst=False, errors='coerce')
df = df.dropna(subset=['cone_depan', 'ketebalan', 'tanggal']).sort_values('tanggal').reset_index(drop=True)
# referensi waktu dari hari pertama operasi
T0 = df['tanggal'].min()
df['hari_ke'] = (df['tanggal'] - T0).dt.days
print(f"✅ Data: {len(df)} baris | {df['tanggal'].min().date()} s/d {df['tanggal'].max().date()}")
print(f" Ketebalan: min={df['ketebalan'].min():.0f}mm | max={df['ketebalan'].max():.0f}mm")
print(f" Pengukuran terakhir: {df['ketebalan'].iloc[-1]:.0f}mm pada {df['tanggal'].iloc[-1].date()}")
# ============================================================
# CELL 3: Hitung Titik Pengukuran & Laju Aus
# ============================================================
#
# INSIGHT: Ketebalan BTA diukur manual secara berkala (tidak harian).
# Data harian hanya mengulang nilai pengukuran terakhir sampai ada
# pengukuran baru. Oleh karena itu, model yang benar adalah:
# Ketebalan_hari_ini = Ketebalan_terakhir_diukur + (laju_aus × hari_berlalu)
#
# Identifikasi titik pengukuran aktual (ketika nilai berubah)
mask_change = df['ketebalan'] != df['ketebalan'].shift(1)
df_ukur = df[mask_change].copy().reset_index(drop=True)
# Hitung laju aus antar pengukuran
df_ukur['delta_tebal'] = df_ukur['ketebalan'].diff() # negatif = menipis
df_ukur['delta_hari'] = df_ukur['hari_ke'].diff()
df_ukur['laju_aus'] = df_ukur['delta_tebal'] / df_ukur['delta_hari'] # mm/hari
# Suhu rata-rata selama periode antar pengukuran
for i in range(1, len(df_ukur)):
h_start = df_ukur.loc[i-1, 'hari_ke']
h_end = df_ukur.loc[i, 'hari_ke']
mask = (df['hari_ke'] >= h_start) & (df['hari_ke'] < h_end)
df_ukur.loc[i, 'suhu_avg_periode'] = df.loc[mask, 'cone_depan'].add(
df.loc[mask, 'body_tengah']).add(df.loc[mask, 'cone_belakang']).div(3).mean()
df_ukur = df_ukur.dropna(subset=['laju_aus'])
# Laju aus statistik
laju_mean = df_ukur['laju_aus'].mean() # mm/hari (negatif)
laju_recent = df_ukur['laju_aus'].tail(5).mean() # laju 5 periode terakhir
print(f"\n📊 Analisis Laju Aus:")
print(f" Rata-rata historis : {laju_mean:.4f} mm/hari")
print(f" Rata-rata 5 terbaru : {laju_recent:.4f} mm/hari")
print(f" Pengukuran terakhir : {df_ukur['ketebalan'].iloc[-1]:.0f}mm "
f"pada hari ke-{df_ukur['hari_ke'].iloc[-1]}")
print(f"\n{df_ukur[['tanggal','ketebalan','delta_hari','laju_aus','suhu_avg_periode']].to_string(index=False)}")
# ============================================================
# CELL 4: Model XGBoost — Prediksi Laju Aus dari Suhu
# ============================================================
#
# Karena laju aus antar periode bervariasi, kita gunakan XGBoost
# untuk mempelajari: "Seberapa cepat BTA menipis berdasarkan suhu?"
# Lalu gunakan laju ini untuk proyeksi ke depan.
#
# Fitur: suhu rata-rata & karakteristik suhu selama satu periode
X_rate = df_ukur[['suhu_avg_periode']].fillna(df_ukur['suhu_avg_periode'].mean())
y_rate = df_ukur['laju_aus'] # target: laju aus (mm/hari)
model_rate = XGBRegressor(
n_estimators = 200,
learning_rate = 0.05,
max_depth = 3,
subsample = 0.8,
random_state = 42
)
model_rate.fit(X_rate, y_rate)
print(f"\n✅ Model laju aus dilatih pada {len(df_ukur)} titik pengukuran.")
# ============================================================
# CELL 5: Fungsi Prediksi Harian (PRODUCTION READY)
# ============================================================
# State terakhir yang diketahui
TEBAL_TERAKHIR = float(df['ketebalan'].iloc[-1]) # mm
TANGGAL_UKUR = df['tanggal'].iloc[-1] # tanggal pengukuran aktual terakhir
HARI_UKUR = int(df['hari_ke'].iloc[-1]) # hari ke- dari pengukuran tsb
# Batas operasi
BATAS_KRITIS = 115.0 # mm
BATAS_WARNING = 130.0 # mm
BATAS_SUHU = 400.0 # °C
WARN_SUHU = 375.0 # °C
def predict_bta_daily(t_depan: float, t_tengah: float, t_belakang: float,
tanggal_cek: str = None,
tebal_aktual: float = None):
"""
Prediksi ketebalan BTA untuk monitoring harian produksi.
Parameters
----------
t_depan : Suhu Cone Depan (°C) hari ini
t_tengah : Suhu Bodi Tengah (°C) hari ini
t_belakang : Suhu Cone Belakang (°C) hari ini
tanggal_cek : Tanggal pengecekan 'DD/MM/YYYY' (default: hari ini)
tebal_aktual : (Opsional) Jika ada hasil pengukuran BTA hari ini,
masukkan di sini untuk update anchor secara otomatis
"""
global TEBAL_TERAKHIR, TANGGAL_UKUR, HARI_UKUR
# Update anchor jika ada pengukuran aktual baru
if tebal_aktual is not None:
TEBAL_TERAKHIR = float(tebal_aktual)
TANGGAL_UKUR = datetime.now() if tanggal_cek is None else datetime.strptime(tanggal_cek, '%d/%m/%Y')
HARI_UKUR = int((TANGGAL_UKUR - T0).days)
print(f"🔄 Anchor diperbarui: {TEBAL_TERAKHIR}mm pada {TANGGAL_UKUR.date()}")
# Tanggal hari ini
tgl_cek = datetime.now() if tanggal_cek is None else datetime.strptime(tanggal_cek, '%d/%m/%Y')
hari_sejak_ukur = (tgl_cek - (TANGGAL_UKUR if isinstance(TANGGAL_UKUR, datetime)
else pd.Timestamp(TANGGAL_UKUR).to_pydatetime())).days
# Suhu hari ini
suhu_avg = (t_depan + t_tengah + t_belakang) / 3
# Prediksi laju aus berdasarkan suhu hari ini
laju_pred = model_rate.predict(pd.DataFrame([[suhu_avg]], columns=['suhu_avg_periode']))[0]
# Koreksi: gunakan weighted average antara laju historis dan prediksi model
# (karena data terbatas, beri bobot lebih ke historis)
laju_efektif = 0.4 * laju_pred + 0.6 * laju_recent
# Proyeksi ketebalan hari ini
tebal_pred = TEBAL_TERAKHIR + (laju_efektif * hari_sejak_ukur)
tebal_pred = max(tebal_pred, 100.0) # floor fisik
# Estimasi sisa hari ke batas kritis
if tebal_pred > BATAS_KRITIS and laju_efektif < 0:
sisa_tebal = tebal_pred - BATAS_KRITIS
sisa_hari = int(sisa_tebal / abs(laju_efektif))
tgl_kritis = tgl_cek + timedelta(days=sisa_hari)
else:
sisa_hari = 0
tgl_kritis = tgl_cek
# Status & alert
if suhu_avg > BATAS_SUHU or tebal_pred < BATAS_KRITIS:
status = "🔴 CRITICAL"
aksi = "SEGERA PERBAIKAN / SLAGGING — Koordinasi maintenance sekarang!"
border = "!"*52
elif suhu_avg > WARN_SUHU or tebal_pred < BATAS_WARNING:
status = "🟡 WARNING"
aksi = "Siapkan jadwal maintenance. Monitor lebih sering."
border = "="*52
else:
status = "🟢 AMAN"
aksi = "Operasi normal. Lanjutkan monitoring rutin."
border = "-"*52
print(f"\n{border}")
print(f" 🏭 BTA DAILY MONITORING — {tgl_cek.strftime('%d %B %Y')}")
print(f"{border}")
print(f" 📡 Input Suhu : Depan={t_depan}°C | Tengah={t_tengah}°C | Belakang={t_belakang}°C")
print(f" 🌡️ Suhu Rata-rata : {suhu_avg:.1f}°C")
print(f" 📅 Anchor Terakhir : {TEBAL_TERAKHIR:.0f}mm ({(TANGGAL_UKUR if isinstance(TANGGAL_UKUR, datetime) else pd.Timestamp(TANGGAL_UKUR).to_pydatetime()).strftime('%d %b %Y')})")
print(f" ⏱️ Hari sejak ukur : {hari_sejak_ukur} hari")
print(f" 📉 Laju Aus Est. : {laju_efektif:.4f} mm/hari")
print(f"{'='*52}")
print(f" 🧱 PREDIKSI TEBAL : {tebal_pred:.1f} mm")
print(f" 📊 Status : {status}")
print(f" ⚡ Aksi : {aksi}")
print(f"{'-'*52}")
if tebal_pred > BATAS_KRITIS:
print(f" ⏳ Estimasi Sisa : ± {sisa_hari} hari lagi")
print(f" 🔧 Est. Kritis : {tgl_kritis.strftime('%d %B %Y')}")
else:
print(f" ⏳ Status : Ketebalan sudah di/bawah batas kritis!")
print(f"{border}\n")
return {
'tebal_prediksi' : round(tebal_pred, 1),
'laju_aus' : round(laju_efektif, 4),
'sisa_hari' : sisa_hari,
'est_kritis' : tgl_kritis.strftime('%d %B %Y'),
'status' : status
}
# ============================================================
# CELL 6: Uji Coba Prediksi
# ============================================================
print("=" * 60)
print("🧪 UJI COBA PREDIKSI HARIAN")
print("=" * 60)
# Contoh 1: Suhu normal
_ = predict_bta_daily(t_depan=378, t_tengah=310, t_belakang=355)
# Contoh 2: Suhu tinggi (mendekati kritis)
_ = predict_bta_daily(t_depan=435, t_tengah=410, t_belakang=372)
# Contoh 3: Suhu rendah (kondisi baik)
_ = predict_bta_daily(t_depan=320, t_tengah=295, t_belakang=340)
# Contoh 4: Ada pengukuran BTA baru hari ini (misal diukur = 118mm)
# Ini akan update anchor sehingga prediksi ke depan lebih akurat
# _ = predict_bta_daily(t_depan=350, t_tengah=320, t_belakang=360, tebal_aktual=118)
# ============================================================
# CELL 7: Visualisasi Historis + Proyeksi
# ============================================================
sns.set_theme(style='whitegrid')
fig, axes = plt.subplots(2, 1, figsize=(16, 12))
fig.suptitle('BTA Thickness Monitoring — Rotary Furnace', fontsize=15, fontweight='bold')
# --- Panel 1: History + Proyeksi ---
ax1 = axes[0]
# Data aktual (stepwise — karena nilai hanya berubah saat diukur)
ax1.step(df['tanggal'], df['ketebalan'], where='post',
color='royalblue', linewidth=2.5, label='Ketebalan Aktual (Pengukuran Manual)', zorder=3)
# Titik pengukuran aktual
ax1.scatter(df_ukur['tanggal'], df_ukur['ketebalan'],
color='royalblue', s=80, zorder=5, label='Titik Pengukuran Aktual')
# Proyeksi 90 hari ke depan
tgl_terakhir = df['tanggal'].max()
proj_hari = 90
proj_dates = [tgl_terakhir + timedelta(days=i) for i in range(0, proj_hari+1)]
# Gunakan laju recent untuk proyeksi
suhu_asumsi = df['cone_depan'].add(df['body_tengah']).add(df['cone_belakang']).div(3).tail(14).mean()
laju_proj = model_rate.predict(pd.DataFrame([[suhu_asumsi]], columns=['suhu_avg_periode']))[0]
laju_proj = 0.4 * laju_proj + 0.6 * laju_recent # weighted
proj_tebal = [max(TEBAL_TERAKHIR + laju_proj * i, 95) for i in range(0, proj_hari+1)]
ax1.plot(proj_dates, proj_tebal,
color='darkorange', linewidth=2, linestyle='--',
label=f'Proyeksi 90 Hari (laju={laju_proj:.4f} mm/hari)', zorder=4)
# Confidence band proyeksi
laju_hi = laju_proj * 0.7 # lebih lambat (optimis)
laju_lo = laju_proj * 1.3 # lebih cepat (pesimis)
proj_hi = [max(TEBAL_TERAKHIR + laju_hi * i, 95) for i in range(0, proj_hari+1)]
proj_lo = [max(TEBAL_TERAKHIR + laju_lo * i, 95) for i in range(0, proj_hari+1)]
ax1.fill_between(proj_dates, proj_lo, proj_hi, alpha=0.15, color='darkorange', label='Range Proyeksi (±30%)')
# Garis batas
ax1.axhline(y=BATAS_KRITIS, color='red', linestyle=':', linewidth=2, label=f'Batas Kritis ({BATAS_KRITIS}mm)')
ax1.axhline(y=BATAS_WARNING, color='orange', linestyle='--', linewidth=1.5, label=f'Batas Warning ({BATAS_WARNING}mm)')
ax1.axvline(x=tgl_terakhir, color='gray', linestyle=':', linewidth=1, label='Data Terakhir')
# Annotasi kapan kritis
for i, (tgl, tp) in enumerate(zip(proj_dates, proj_tebal)):
if tp <= BATAS_KRITIS:
ax1.annotate(f'Est. Kritis:\n{tgl.strftime("%d %b %Y")}',
xy=(tgl, BATAS_KRITIS), xytext=(-100, 30),
textcoords='offset points', color='red', fontsize=9, fontweight='bold',
arrowprops=dict(arrowstyle='->', color='red', lw=1.5))
break
ax1.set_title('Historis Ketebalan BTA & Proyeksi ke Depan', fontsize=12)
ax1.set_ylabel('Ketebalan (mm)')
ax1.legend(loc='upper right', fontsize=8.5)
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
plt.setp(ax1.xaxis.get_majorticklabels(), rotation=30)
ax1.set_ylim(90, 245)
# --- Panel 2: Suhu Monitoring ---
ax2 = axes[1]
suhu_avg_series = (df['cone_depan'] + df['body_tengah'] + df['cone_belakang']) / 3
ma7 = suhu_avg_series.rolling(7, min_periods=1).mean()
ax2.plot(df['tanggal'], suhu_avg_series, color='lightcoral', alpha=0.35, linewidth=1, label='Suhu Avg (Raw)')
ax2.plot(df['tanggal'], ma7, color='crimson', linewidth=2, label='Suhu Avg MA-7')
ax2.axhline(y=BATAS_SUHU, color='darkred', linestyle='--', linewidth=1.5, label=f'Batas Suhu ({BATAS_SUHU}°C)')
ax2.axhline(y=WARN_SUHU, color='orange', linestyle=':', linewidth=1.2, label=f'Warning Suhu ({WARN_SUHU}°C)')
ax2.axvline(x=tgl_terakhir, color='gray', linestyle=':', linewidth=1)
ax2.set_title('Monitoring Suhu Harian', fontsize=12)
ax2.set_ylabel('Suhu (°C)')
ax2.set_xlabel('Tanggal')
ax2.legend(fontsize=8.5)
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax2.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
plt.setp(ax2.xaxis.get_majorticklabels(), rotation=30)
plt.tight_layout()
output_monitoring = f'bta_monitoring_{base_name}.png'
plt.savefig(output_monitoring, dpi=150, bbox_inches='tight')
plt.show()
print(f"✅ Grafik disimpan: '{output_monitoring}'")
# ============================================================
# CELL 8: Simpan Model & State
# ============================================================
import pickle
output_model = f'model_rate_{base_name}.pkl'
with open(output_model, 'wb') as f:
pickle.dump(model_rate, f)
# Simpan juga dalam format native JSON untuk kompatibilitas Hugging Face
output_model_json = f'model_rate_{base_name}.json'
model_rate.save_model(output_model_json)
model_rate.save_model('xgboost_bta.json')
state = {
'T0' : T0,
'tebal_terakhir' : TEBAL_TERAKHIR,
'tanggal_ukur' : TANGGAL_UKUR,
'hari_ukur' : HARI_UKUR,
'laju_mean' : laju_mean,
'laju_recent' : laju_recent,
'batas_kritis' : BATAS_KRITIS,
'batas_warning' : BATAS_WARNING,
}
output_state = f'bta_state_{base_name}.pkl'
with open(output_state, 'wb') as f:
pickle.dump(state, f)
print("\n✅ Model & State disimpan:")
print(f" 📦 {output_model} — Model laju aus XGBoost (Pickle)")
print(f" 📦 xgboost_bta.json — Model laju aus XGBoost (JSON - HF compatible)")
print(f" 📦 {output_state} — State pengukuran terakhir")
print("\n💡 TIP PENGGUNAAN HARIAN:")
print(" Setiap ada pengukuran BTA baru, gunakan parameter tebal_aktual=XXX")
print(" agar anchor diperbarui dan prediksi makin akurat.")
print(" Contoh: predict_bta_daily(350, 320, 360, tebal_aktual=118)")
"""##ACTUAL VS PREDICT"""
import pandas as pd
pred_values = []
pred_dates = []
# set patokan awal dari data pertama
current_anchor = df['ketebalan'].iloc[0]
anchor_date = df['tanggal'].iloc[0]
for index, row in df.iterrows():
# update patokan kalau ada data ukur manual di hari itu
if row['tanggal'] in df_ukur['tanggal'].values:
current_anchor = row['ketebalan']
anchor_date = row['tanggal']
suhu_avg = (row['cone_depan'] + row['body_tengah'] + row['cone_belakang']) / 3
# jalanin modelnya buat nebak laju aus
laju_pred = model_rate.predict(pd.DataFrame([[suhu_avg]], columns=['suhu_avg_periode']))[0]
# gabungin tebakan model sama rata-rata laju terbaru biar stabil
laju_efektif = 0.4 * laju_pred + 0.6 * laju_recent
hari_sejak = (row['tanggal'] - anchor_date).days
tebal_pred = current_anchor + (laju_efektif * hari_sejak)
pred_values.append(tebal_pred)
pred_dates.append(row['tanggal'])
# jadiin format series sesuai yang diminta matplotlib kamu
historical_predictions = pd.Series(pred_values, index=pred_dates)
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
# Ensure necessary variables are available from previous cells.
# df, df_ukur, historical_predictions, BATAS_KRITIS, BATAS_WARNING
# Plotting the comparison
fig, ax = plt.subplots(figsize=(16, 8))
# Actual BTA thickness (stepwise)
ax.step(df['tanggal'], df['ketebalan'], where='post',
color='royalblue', linewidth=2.5, label='Ketebalan Aktual (Pengukuran Manual)', zorder=3)
ax.scatter(df_ukur['tanggal'], df_ukur['ketebalan'],
color='royalblue', s=80, zorder=5, label='Titik Pengukuran Aktual')
# Predicted BTA thickness (model-based) - using the pre-calculated historical_predictions
ax.plot(historical_predictions.index, historical_predictions.values,
color='darkgreen', linestyle='-', linewidth=1.5, label='Prediksi Model Harian', zorder=2)
# Add thresholds
ax.axhline(y=BATAS_KRITIS, color='red', linestyle=':', linewidth=2, label=f'Batas Kritis ({BATAS_KRITIS}mm)')
ax.axhline(y=BATAS_WARNING, color='orange', linestyle='--', linewidth=1.5, label=f'Batas Warning ({BATAS_WARNING}mm)')
ax.set_title('Perbandingan Ketebalan BTA Aktual vs. Prediksi Model Historis', fontsize=15, fontweight='bold')
ax.set_ylabel('Ketebalan (mm)')
ax.set_xlabel('Tanggal')
ax.legend(loc='upper right', fontsize=10)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
plt.setp(ax.xaxis.get_majorticklabels(), rotation=30)
ax.set_ylim(90, 245) # Consistent y-axis with previous plots
plt.grid(True)
plt.tight_layout()
output_comparison = f'bta_comparison_{base_name}.png'
plt.savefig(output_comparison, dpi=150, bbox_inches='tight')
plt.show()
print(f"✅ Grafik perbandingan aktual vs. prediksi historis ditampilkan dan disimpan ke '{output_comparison}'.")
# Input suhu dari pengguna
t_depan_input = float(input("Masukkan suhu Cone Depan (°C): "))
t_tengah_input = float(input("Masukkan suhu Bodi Tengah (°C): "))
t_belakang_input = float(input("Masukkan suhu Cone Belakang (°C): "))
# Panggil fungsi prediksi dengan input suhu
result = predict_bta_daily(t_depan=t_depan_input,
t_tengah=t_tengah_input,
t_belakang=t_belakang_input)
print("\nRingkasan Prediksi:")
for key, value in result.items():
print(f"- {key.replace('_', ' ').title()}: {value}")