""" 모델 JSON export → C# SteamAdvisor에서 로드. 선형근사(1안): GBM 대신 LinearRegression 계수 export. steam = w0 + w1*feed + w2*product + w3*T_C valve_inv(flow) = poly3 → OP 사용법: python3 c6111_export_model.py --data c6111_data.pkl --prefix c6111 """ import argparse import json import numpy as np import pandas as pd from sklearn.linear_model import LinearRegression BASE = "/home/windpacer/projects/hc900_ax/scripts/analysis/" FEATURES = ["feed", "product", "T_C"] def main(): parser = argparse.ArgumentParser() parser.add_argument("--data", default=BASE + "C-6111_data.pkl") parser.add_argument("--prefix", default="C-6111") parser.add_argument("--output", help="JSON 출력 경로 (기본: scripts/analysis/{prefix}_model.json)") args = parser.parse_args() df = pd.read_pickle(args.data) prod = df[df["mode"] == "PROD"].copy() prod = prod[(prod["feed"] > 50) & (prod["steam_flow"] > 10) & (prod["steam_op"] > 1)] prod = prod.dropna(subset=FEATURES + ["steam_op", "steam_flow"]) ops = (prod.set_index("dtat").resample("6h").median(numeric_only=True) .dropna(subset=["steam_flow", "feed"])) ops = ops[ops["feed"] > 50] # 선형 모델 lr = LinearRegression() lr.fit(ops[FEATURES].values, ops["steam_flow"].values) r2 = lr.score(ops[FEATURES].values, ops["steam_flow"].values) print(f"선형 steam_flow R² = {r2:.4f} (GBM 대비 비교용)") # 밸브 역특성: steam_flow → steam_op (3차) vp = np.polyfit(prod["steam_flow"], prod["steam_op"], 3) # Envelope (1%, 99%) lo = ops[FEATURES].quantile(0.01) hi = ops[FEATURES].quantile(0.99) # GBM feature importance (참고용) try: from sklearn.ensemble import GradientBoostingRegressor gbm = GradientBoostingRegressor(n_estimators=200, max_depth=2, learning_rate=0.05, random_state=0) gbm.fit(ops[FEATURES].values, ops["steam_flow"].values) gbm_r2 = gbm.score(ops[FEATURES].values, ops["steam_flow"].values) except Exception: gbm_r2 = None model = { "column": args.prefix, "features": FEATURES, "linear_coeffs": lr.coef_.tolist(), "intercept": lr.intercept_, "linear_r2": round(r2, 4), "gbm_r2": round(gbm_r2, 4) if gbm_r2 else None, "valve_poly": vp.tolist(), "envelope_lo": {c: round(float(lo[c]), 1) for c in FEATURES}, "envelope_hi": {c: round(float(hi[c]), 1) for c in FEATURES}, "n_operating_points": len(ops), "n_prod_rows": len(prod), } out = args.output or (BASE + f"{args.prefix}_model.json") with open(out, "w") as f: json.dump(model, f, indent=2) print(f"\n모델 export: {out}") print(json.dumps(model, indent=2)) if __name__ == "__main__": main()