AL-mozahem's picture
Publish HRP Stage 07 original CatBoost occupancy model
a1f48d9 verified
Raw History Blame Contribute Delete
2.68 kB
from pathlib import Path
import argparse,json
import pandas as pd
import joblib
ROOT=Path(__file__).resolve().parents[1]
MODELS=ROOT/"models"
def load_artifacts():
metadata=json.loads((MODELS/"model_metadata.json").read_text(encoding="utf-8"))
model=joblib.load(MODELS/"final_model.joblib")
medians={}
median_file=MODELS/"catboost_numeric_medians.json"
if median_file.exists():
medians=json.loads(median_file.read_text(encoding="utf-8"))
preprocessor=None
pp=MODELS/"final_preprocessor.joblib"
if pp.exists():
preprocessor=joblib.load(pp)
return metadata,model,medians,preprocessor
def _prepare_catboost(features,metadata,medians):
required=metadata["feature_columns"]
row=pd.DataFrame([{c:features.get(c) for c in required}])
for c in metadata["numeric_columns"]:
row[c]=pd.to_numeric(row[c],errors="coerce").fillna(float(medians[c]))
for c in metadata["categorical_columns"]:
row[c]=row[c].astype("object").where(row[c].notna(),"MISSING").astype(str)
return row[required]
def predict_next7d_occupancy(features:dict)->dict:
metadata,model,medians,preprocessor=load_artifacts()
required=metadata["feature_columns"]
missing=[c for c in required if c not in features]
if missing:
raise ValueError(f"Missing required features: {missing}")
if metadata["model_kind"]=="catboost_native":
row=_prepare_catboost(features,metadata,medians)
pred=float(model.predict(row)[0])
else:
row=pd.DataFrame([{c:features.get(c) for c in required}])
pred=float(model.predict(preprocessor.transform(row))[0])
pred=max(0.0,min(1.0,pred))
on_books=float(features["on_books_occupancy_next_7d"])
expected_increment=max(0.0,pred-on_books)
return {
"predicted_next_7d_occupancy_rate":round(pred,6),
"predicted_next_7d_occupancy_percent":round(pred*100,2),
"on_books_occupancy_rate":round(on_books,6),
"expected_additional_occupancy_rate":round(expected_increment,6),
"model_name":metadata["selected_algorithm"],
"forecast_window":"next 7 days",
"decision_support_only":True,
"synthetic_training_data_warning":metadata["synthetic_training_data"],
"production_warning":metadata["production_warning"]
}
def main():
parser=argparse.ArgumentParser()
parser.add_argument("json_file")
args=parser.parse_args()
payload=json.loads(Path(args.json_file).read_text(encoding="utf-8"))
print(json.dumps(
predict_next7d_occupancy(payload.get("features",payload)),
ensure_ascii=False,indent=2
))
if __name__=="__main__":
main()