184 lines
4.1 KiB
Python
184 lines
4.1 KiB
Python
import pandas as pd
|
|
import numpy as np
|
|
from sqlalchemy import create_engine, text
|
|
import joblib
|
|
import os
|
|
from datetime import datetime
|
|
|
|
# =========================
|
|
# DB
|
|
# =========================
|
|
user = "root"
|
|
password = ""
|
|
host = "localhost"
|
|
db = "udd_pmi_module"
|
|
engine = create_engine(
|
|
f"mysql+pymysql://{user}:{password}@{host}/{db}"
|
|
)
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
MODEL_PATH = os.path.join(BASE_DIR, "model.pkl")
|
|
saved = joblib.load(MODEL_PATH)
|
|
model = saved["model"]
|
|
usage_bins = saved["usage_bins"]
|
|
|
|
# =========================
|
|
# AMBIL SEMUA BARANG
|
|
# =========================
|
|
items = pd.read_sql(
|
|
"""
|
|
SELECT DISTINCT kode
|
|
FROM item_usage_monthly
|
|
ORDER BY kode
|
|
""",
|
|
engine,
|
|
)
|
|
|
|
# =========================
|
|
# HAPUS DATA PREDIKSI LAMA
|
|
# =========================
|
|
with engine.begin() as conn:
|
|
conn.execute(text("""
|
|
DELETE FROM prediction_results
|
|
"""))
|
|
|
|
# =========================
|
|
# FEATURE BUILDER
|
|
# =========================
|
|
def build_features(history, bulan):
|
|
lag = history[-6:]
|
|
ma_6 = np.mean(lag)
|
|
trend_3 = lag[-1] - np.mean(
|
|
[lag[-2], lag[-3], lag[-4]]
|
|
)
|
|
momentum_1 = lag[-1] - lag[-2]
|
|
momentum_2 = lag[-2] - lag[-3]
|
|
rolling_std_6 = np.std(
|
|
lag,
|
|
ddof=1
|
|
)
|
|
max_6 = np.max(lag)
|
|
min_6 = np.min(lag)
|
|
range_6 = max_6 - min_6
|
|
cv_6 = rolling_std_6 / (ma_6 + 1)
|
|
growth_rate = (
|
|
(lag[-1] - lag[-2])
|
|
/
|
|
(lag[-2] + 1)
|
|
)
|
|
usage_level = pd.cut(
|
|
[ma_6],
|
|
bins=usage_bins,
|
|
labels=False,
|
|
include_lowest=True
|
|
)[0]
|
|
if pd.isna(usage_level):
|
|
usage_level = 0
|
|
quarter = ((bulan-1)//3)+1
|
|
return pd.DataFrame([{
|
|
"lag_1":lag[-1],
|
|
"lag_2":lag[-2],
|
|
"lag_3":lag[-3],
|
|
"lag_4":lag[-4],
|
|
"lag_5":lag[-5],
|
|
"lag_6":lag[-6],
|
|
"ma_6":ma_6,
|
|
"trend_3":trend_3,
|
|
"momentum_1":momentum_1,
|
|
"momentum_2":momentum_2,
|
|
"rolling_std_6":rolling_std_6,
|
|
"max_6":max_6,
|
|
"min_6":min_6,
|
|
"range_6":range_6,
|
|
"cv_6":cv_6,
|
|
"growth_rate":growth_rate,
|
|
"usage_level":usage_level,
|
|
"bulan":bulan,
|
|
"quarter":quarter,
|
|
"is_awal_tahun":int(
|
|
bulan in [1,2,3]
|
|
),
|
|
"is_tengah_tahun":int(
|
|
bulan in [6,7,8]
|
|
),
|
|
"is_akhir_tahun":int(
|
|
bulan in [10,11,12]
|
|
)
|
|
}])
|
|
|
|
# =========================
|
|
# MAIN
|
|
# =========================
|
|
results=[]
|
|
for kode in items["kode"]:
|
|
hist=pd.read_sql(
|
|
f"""
|
|
SELECT
|
|
tahun,
|
|
bulan,
|
|
total_pemakaian
|
|
FROM item_usage_monthly
|
|
WHERE kode='{kode}'
|
|
ORDER BY tahun,bulan
|
|
""",
|
|
engine
|
|
)
|
|
if hist.empty:
|
|
continue
|
|
hist["total_pemakaian"]=pd.to_numeric(
|
|
hist["total_pemakaian"],
|
|
errors="coerce"
|
|
).fillna(0)
|
|
if len(hist)<18:
|
|
print(
|
|
f"SKIP {kode}: data < 18"
|
|
)
|
|
continue
|
|
target_hist=hist.tail(12)
|
|
for idx in target_hist.index:
|
|
start_idx=idx-6
|
|
history=hist.iloc[
|
|
start_idx:idx
|
|
]["total_pemakaian"].tolist()
|
|
if len(history)<6:
|
|
continue
|
|
bulan_target=int(
|
|
hist.loc[idx,"bulan"]
|
|
)
|
|
tahun_target=int(
|
|
hist.loc[idx,"tahun"]
|
|
)
|
|
X=build_features(
|
|
history,
|
|
bulan_target
|
|
)
|
|
pred_log=model.predict(
|
|
X
|
|
)[0]
|
|
pred=np.expm1(
|
|
pred_log
|
|
)
|
|
pred=np.clip(
|
|
round(pred),
|
|
0,
|
|
None
|
|
)
|
|
results.append({
|
|
"kode":kode,
|
|
"bulan_prediksi":bulan_target,
|
|
"tahun_prediksi":tahun_target,
|
|
"jumlah_prediksi":int(pred),
|
|
"tanggal_prediksi":datetime.now().date()
|
|
})
|
|
|
|
# =========================
|
|
# INSERT
|
|
# =========================
|
|
if results:
|
|
df_insert=pd.DataFrame(results)
|
|
df_insert.to_sql(
|
|
"prediction_results",
|
|
engine,
|
|
if_exists="append",
|
|
index=False
|
|
)
|
|
print("SELESAI") |