From 9c1d9efbf8807d834758d820fd5862046c2fb446 Mon Sep 17 00:00:00 2001 From: rahel_yab Date: Sun, 14 Dec 2025 19:16:43 +0300 Subject: [PATCH] implemented train.py --- models/logistic_regression.pkl | Bin 0 -> 5498 bytes src/train.py | 130 +++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 models/logistic_regression.pkl diff --git a/models/logistic_regression.pkl b/models/logistic_regression.pkl new file mode 100644 index 0000000000000000000000000000000000000000..de2f665c0820fea9816e9b076ef818a2565cd4cc GIT binary patch literal 5498 zcmcIodvH|M8Q<(HyGzJJs(_$~SV3AA2;u$MC2L4z?Sh~sEoCluchBZra$np>LKxa1 zI)r5AOr?4kAEl0U+NnDBMeB5|)437r_+Tn+nc5DtsfAJmEVfW5IE>Qo+{Zpb!a&CC zAIbT4&;1_1^ZUN@eRsD%|24nI`jA?+oky%9MrBS$JSQT9gx0&u$Blcsjc*#WNI=z) ztQuQjStTn-R-_D4RY@_(4EOnrB*>DAqD)5ObwOk_g%#DDqzDLh)g`PiA1wKVkp2wrw2PVvwMkVR@=(ifgXu1t+#enJlZZ2C3etv0|20vK#H~1smZ`PQ#3V zSkdSuAxluTEUf(*N$!IGwTz>f=|GCgNuogl^P@|m^9()RW3Z&A;3UI|vaT5^5)_ai zDP6FtglEzayU~ZI;@k8zg(OVYMNV zN+QA%JU4BGNRgP4vf!gZ#;+4mi=;K#Ul@g8BcK$uNeYKxlb_W!3HGWotEh;Pbd7r7 zM*>-`O9r#1@Co(w& zZP&pa3PH8N?qEvnrpV1X#A>>N7?BkakU~fUx!?qY8A-IFwx9xR@w61aBZa4zfLE2! z6@_X}K&S>8m!ME8juct1NF5wNa9`FSVGy!lvW|K35AnK3e$o8;n^=AF0@7q*AH1SKwp)NyaoIO(HDMOP!1$urknRitU?ahhcf(hkzi| zbe9ICOV;Y?-GO{Fy7l>U>N=8~RB=B%}E&HZC4g4M}8Yi3&_%;Fw6r zsh?IQ#CPI2BDa;+Qbv>P3Iu<%98_UipK%RDm<%Q>lOcp>(zPd9k@O~gNq;hcaLX1W z8D@17DN@nEEqECe)^hh)C`r|2m4bn@9$%6HDnl;;TvJ+|@dSK}Q>!QU;#+(1lwQ0J zZ*abP2yeozNgtfr*YRfH-Bz6G!&!$SKX#G$Tq#10jfNuEQM0Y{d)o0DBgmE-kx^Me z=8?*%2+{N%F&66ZR>a*|b>(c1Ga^=YrPu2bAUzg*}O$Sz-ICeRHbnD!~ zxjRqC^2E_+U#nN&75L7*2A)~Q#V_HgL%jL89xvzv#x2H6@KU@ig_o!BiWFXnSCI*j zJuA(k!EKh*=h@k<}5tU#h0Hk zyqOVb_0KT@Yt*zVwpq-4xF|}*`f_nWx!6!HE-V)pId|X)&`cbjN5{sbm7vCMoJX_B zxI)wEB4f9p%=~$Fu&(If=86t(uIS+AiVkkB=-}pxi^?@Gg|4{hMY-boaxd!3y{I3u zx!jBTaxdx^m)U{6C01c;i3I+ZNZ@XXRIX)7*>6j)O^ERDgt#y!xk8PNh7gr3r)Zo2 zO?nj_M47Zs=O@)5H|02y6*C;mLvx^XSp6CdjxfK_Ujvect&vEB79Uze61F-mSyEu_ z)jB|(u5mo4bunp<=dTTve|Vq{jR{cH*l2(nR~X1>=9EZ4$`Xn4thjTb6ZlPDI~GJH zF?0@PxaM>wG&706x&m|$t3N+P2+g)#g=Pwj);Og=l*bUUV zG(7or&NnbuTIR1(T5MnF#otgIhOc??S2|{=f%^O$*G3>Cq1@FLl5>095vbUw2P_RQ z|1!4scZuiBPb!0Ff6y3-|FEI^?Bp}=$5#L9^r?L(ef`1*_W#qVhwoZG5bQtnz*AdR z?Rv!g-nPqi=Xz@5XBP7l2D;Ci&vd+dapr;A{_16CeiG=v6dQN&!+VY%`LFq%U;K94 zz-z~2E4SC*`{vFw=9-<)J^Pn|edfXN^49*3-jD5W>W&Up51My>V{pf@w~oj5uX}NG zFX}P1?Y+DH{=}cn!;ksDJNw=@%r)P7z0qIwp&6L*TFdL=1+!iAZ1tXc)%5)APiKxi zu)v&s{H5=|Z5}dD{ye^YOLQ4>YXu z#$Elc|E@o--UXBD-u!fRMgNc1Ht)%8J8gQJPVb-jM6iG0#ryu+eEWOm8*^T6pZfg& zVjI}zFaBCNY3Ap-XBH_keJJ0G)F>X?5Wcm)vajc^zXkjAlO26-exo7pwxa(Bz{aw9 literal 0 HcmV?d00001 diff --git a/src/train.py b/src/train.py index e69de29..c0a4d36 100644 --- a/src/train.py +++ b/src/train.py @@ -0,0 +1,130 @@ +import os +import joblib +import pandas as pd + +from sklearn.model_selection import train_test_split +from sklearn.pipeline import Pipeline +from sklearn.compose import ColumnTransformer +from sklearn.preprocessing import StandardScaler, OneHotEncoder +from sklearn.linear_model import LogisticRegression +from sklearn.metrics import classification_report, roc_auc_score + + +DATA_PATH = "data/processed/transactions_with_target.csv" +MODEL_DIR = "models" +TARGET_COL = "FraudResult" + + +# Columns to drop (identifiers, not features) +DROP_COLS = [ + "TransactionId", + "BatchId", + "AccountId", + "SubscriptionId", + "CustomerId", + "TransactionStartTime" +] + + +def load_data(path: str) -> pd.DataFrame: + if not os.path.exists(path): + raise FileNotFoundError(f"Data file not found at {path}") + return pd.read_csv(path) + + +def build_preprocessor(df: pd.DataFrame) -> ColumnTransformer: + numeric_features = [ + "Amount", + "Value", + "PricingStrategy" + ] + + categorical_features = [ + "CurrencyCode", + "CountryCode", + "ProviderId", + "ProductId", + "ProductCategory", + "ChannelId" + ] + + numeric_pipeline = Pipeline( + steps=[ + ("scaler", StandardScaler()) + ] + ) + + categorical_pipeline = Pipeline( + steps=[ + ("onehot", OneHotEncoder(handle_unknown="ignore", sparse_output=False)) + ] + ) + + preprocessor = ColumnTransformer( + transformers=[ + ("num", numeric_pipeline, numeric_features), + ("cat", categorical_pipeline, categorical_features) + ] + ) + + return preprocessor + + +def build_model(preprocessor: ColumnTransformer) -> Pipeline: + model = Pipeline( + steps=[ + ("preprocessor", preprocessor), + ("classifier", LogisticRegression( + max_iter=1000, + class_weight="balanced", + n_jobs=-1 + )) + ] + ) + return model + + +def main(): + print("Loading data...") + df = load_data(DATA_PATH) + + df = df.drop(columns=DROP_COLS, errors="ignore") + + X = df.drop(columns=[TARGET_COL]) + y = df[TARGET_COL] + + print("Splitting data...") + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + test_size=0.2, + stratify=y, + random_state=42 + ) + + print("Building model...") + preprocessor = build_preprocessor(df) + model = build_model(preprocessor) + + print("Training model...") + model.fit(X_train, y_train) + + print("Evaluating model...") + y_pred = model.predict(X_test) + y_proba = model.predict_proba(X_test)[:, 1] + + print("\nClassification Report:") + print(classification_report(y_test, y_pred)) + + roc_auc = roc_auc_score(y_test, y_proba) + print(f"ROC-AUC: {roc_auc:.4f}") + + os.makedirs(MODEL_DIR, exist_ok=True) + model_path = os.path.join(MODEL_DIR, "logistic_regression.pkl") + joblib.dump(model, model_path) + + print(f"\nModel saved to {model_path}") + + +if __name__ == "__main__": + main()