mlforgex 1.0.2__tar.gz → 1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mlforgex-1.0.2/mlforgex.egg-info → mlforgex-1.0.4}/PKG-INFO +2 -4
- {mlforgex-1.0.2 → mlforgex-1.0.4}/README.md +1 -1
- mlforgex-1.0.4/mlforge/predict.py +44 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforge/train.py +103 -44
- {mlforgex-1.0.2 → mlforgex-1.0.4/mlforgex.egg-info}/PKG-INFO +2 -4
- {mlforgex-1.0.2 → mlforgex-1.0.4}/setup.py +1 -2
- mlforgex-1.0.4/test/test_basic.py +9 -0
- mlforgex-1.0.2/mlforge/predict.py +0 -23
- mlforgex-1.0.2/test/test_basic.py +0 -9
- {mlforgex-1.0.2 → mlforgex-1.0.4}/LICENSE +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforge/__init__.py +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforgex.egg-info/SOURCES.txt +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforgex.egg-info/dependency_links.txt +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforgex.egg-info/entry_points.txt +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforgex.egg-info/requires.txt +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/mlforgex.egg-info/top_level.txt +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/pyproject.toml +0 -0
- {mlforgex-1.0.2 → mlforgex-1.0.4}/setup.cfg +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mlforgex
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Lightweight ML utility for automated training, evaluation, and prediction with CLI and Python API support
|
|
5
|
-
Home-page: https://github.com/yourusername/mlforge
|
|
6
5
|
Author: Priyanshu Mathur
|
|
7
6
|
Author-email: mathurpriyanshu2006@gmail.com
|
|
8
7
|
License: MIT
|
|
@@ -24,14 +23,13 @@ Dynamic: author-email
|
|
|
24
23
|
Dynamic: classifier
|
|
25
24
|
Dynamic: description
|
|
26
25
|
Dynamic: description-content-type
|
|
27
|
-
Dynamic: home-page
|
|
28
26
|
Dynamic: license
|
|
29
27
|
Dynamic: license-file
|
|
30
28
|
Dynamic: requires-dist
|
|
31
29
|
Dynamic: requires-python
|
|
32
30
|
Dynamic: summary
|
|
33
31
|
|
|
34
|
-
# mlforgex
|
|
32
|
+
# mlforgex [](https://pepy.tech/projects/mlforgex)
|
|
35
33
|
|
|
36
34
|
**mlforgex** is a Python package that enables easy training, evaluation, and prediction for machine learning models on cleaned dataset. It supports both classification and regression problems, automates preprocessing, model selection, hyperparameter tuning, and generates useful artifacts and plots for analysis.
|
|
37
35
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# mlforgex
|
|
1
|
+
# mlforgex [](https://pepy.tech/projects/mlforgex)
|
|
2
2
|
|
|
3
3
|
**mlforgex** is a Python package that enables easy training, evaluation, and prediction for machine learning models on cleaned dataset. It supports both classification and regression problems, automates preprocessing, model selection, hyperparameter tuning, and generates useful artifacts and plots for analysis.
|
|
4
4
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import pickle;
|
|
2
|
+
import pandas as pd;
|
|
3
|
+
def predict(model_path,preprocessor_path,input_data, encoder_path=None):
|
|
4
|
+
"""
|
|
5
|
+
Load a trained model and make predictions on input data.
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
model_path (str):
|
|
9
|
+
Path to the serialized trained model file.
|
|
10
|
+
preprocessor_path (str):
|
|
11
|
+
Path to the serialized preprocessor file (used for feature transformation).
|
|
12
|
+
input_data (str):
|
|
13
|
+
Path to the input CSV file containing data for prediction.
|
|
14
|
+
encoder_path (Optional[str], optional):
|
|
15
|
+
Path to the serialized encoder file (for categorical target encoding). Defaults to None.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
List[Any]:
|
|
19
|
+
List of predictions generated by the model.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
>>> predict("model.pkl", "preprocessor.pkl", "input.csv")
|
|
23
|
+
[1, 0, 1]
|
|
24
|
+
"""
|
|
25
|
+
print("Loading the pickled model and preprocessor...")
|
|
26
|
+
model = pickle.load(open(model_path, 'rb'))
|
|
27
|
+
preprocessor = pickle.load(open(preprocessor_path, 'rb'))
|
|
28
|
+
encoder = pickle.load(open(encoder_path, 'rb')) if encoder_path else None
|
|
29
|
+
df= pd.read_csv(input_data)
|
|
30
|
+
X = preprocessor.transform(df)
|
|
31
|
+
predictions = model.predict(X)
|
|
32
|
+
if encoder_path:
|
|
33
|
+
predictions = encoder.inverse_transform(predictions)
|
|
34
|
+
return {"prediction": predictions.tolist()}
|
|
35
|
+
def main():
|
|
36
|
+
import argparse
|
|
37
|
+
parser = argparse.ArgumentParser()
|
|
38
|
+
parser.add_argument("--model_path", required=True,help="Path to the model file")
|
|
39
|
+
parser.add_argument("--input_data", required=True,help="Path to the input data CSV file")
|
|
40
|
+
parser.add_argument("--preprocessor_path", required=True,help="Path to the preprocessor file")
|
|
41
|
+
parser.add_argument("--encoder_path", required=False,help="Path to the encoder file")
|
|
42
|
+
args = parser.parse_args()
|
|
43
|
+
print(predict(args.model_path, args.preprocessor_path, args.input_data, args.encoder_path))
|
|
44
|
+
|
|
@@ -26,6 +26,21 @@ from sklearn.model_selection import learning_curve
|
|
|
26
26
|
import warnings
|
|
27
27
|
warnings.filterwarnings("ignore")
|
|
28
28
|
def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=100,cv=3,artifacts_dir=None):
|
|
29
|
+
"""
|
|
30
|
+
Trains a machine learning model using the provided dataset and parameters.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
data_path (str): Path to the CSV dataset file.
|
|
34
|
+
dependent_feature (str): The target column (dependent variable) in the dataset.
|
|
35
|
+
rmse_prob (float): Probability threshold for RMSE (used in regression).
|
|
36
|
+
f1_prob (float): Probability threshold for F1 score (used in classification).
|
|
37
|
+
n_jobs (int, optional): Number of parallel jobs to run (-1 uses all CPUs). Default is -1.
|
|
38
|
+
n_iter (int, optional): Number of iterations for parameter search. Default is 100.
|
|
39
|
+
cv (int, optional): Number of cross-validation folds. Default is 3.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
dict: Model evaluation metrics and trained model object.
|
|
43
|
+
"""
|
|
29
44
|
if artifacts_dir:
|
|
30
45
|
artifacts_path = os.path.join(artifacts_dir, "artifacts")
|
|
31
46
|
else:
|
|
@@ -38,7 +53,7 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
38
53
|
# os.remove(data_path)
|
|
39
54
|
df.head()
|
|
40
55
|
print("Data loaded successfully")
|
|
41
|
-
|
|
56
|
+
df.replace(["", "NA", "na", "N/A", "n/a", "?", "--"], np.nan, inplace=True)
|
|
42
57
|
for i in df.columns:
|
|
43
58
|
if df[i].dtype=="object":
|
|
44
59
|
df[i] = df[i].fillna(df[i].mode()[0])
|
|
@@ -117,6 +132,8 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
117
132
|
print("Categorical features : ",cat_features)
|
|
118
133
|
print("Numerical features : ",num_features)
|
|
119
134
|
if classification:
|
|
135
|
+
is_multiclass = len(set(y_train)) > 2
|
|
136
|
+
average_type = "weighted" if is_multiclass else "binary"
|
|
120
137
|
print("Balancing the dataset...")
|
|
121
138
|
if mild :
|
|
122
139
|
from imblearn.under_sampling import RandomUnderSampler
|
|
@@ -245,7 +262,7 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
245
262
|
"AdaBoostClassifier":AdaBoostClassifier(),
|
|
246
263
|
"XGBClassifier":XGBClassifier(),
|
|
247
264
|
"KNeighborsClassifier":KNeighborsClassifier(),
|
|
248
|
-
"SVC":SVC()
|
|
265
|
+
"SVC":SVC(probability=True)
|
|
249
266
|
}
|
|
250
267
|
|
|
251
268
|
for i in range(len(list(models))):
|
|
@@ -258,15 +275,26 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
258
275
|
|
|
259
276
|
# Training set performance
|
|
260
277
|
model_train_accuracy = accuracy_score(y_train, y_train_pred) # Calculate Accuracy
|
|
261
|
-
model_train_f1 = f1_score(y_train, y_train_pred, average=
|
|
262
|
-
model_train_precision = precision_score(y_train, y_train_pred) # Calculate Precision
|
|
263
|
-
model_train_recall = recall_score(y_train, y_train_pred) # Calculate Recall
|
|
264
|
-
|
|
278
|
+
model_train_f1 = f1_score(y_train, y_train_pred, average=average_type) # Calculate F1-score
|
|
279
|
+
model_train_precision = precision_score(y_train, y_train_pred, average=average_type) # Calculate Precision
|
|
280
|
+
model_train_recall = recall_score(y_train, y_train_pred, average=average_type) # Calculate Recall
|
|
281
|
+
if average_type == "binary":
|
|
282
|
+
y_train_prob = model.predict_proba(x_train)[:,1]
|
|
283
|
+
model_train_rocauc_score = roc_auc_score(y_train, y_train_prob)
|
|
284
|
+
else:
|
|
285
|
+
y_train_prob=model.predict_proba(x_train)
|
|
286
|
+
model_train_rocauc_score = roc_auc_score(y_train, y_train_prob,multi_class='ovr',average=average_type) #Calculate Roc Auc Score
|
|
265
287
|
# Test set performance
|
|
266
288
|
model_test_accuracy = accuracy_score(y_test, y_test_pred) # Calculate Accuracy
|
|
267
|
-
model_test_f1 = f1_score(y_test, y_test_pred, average=
|
|
268
|
-
model_test_precision = precision_score(y_test, y_test_pred) # Calculate Precision
|
|
269
|
-
model_test_recall = recall_score(y_test, y_test_pred) # Calculate
|
|
289
|
+
model_test_f1 = f1_score(y_test, y_test_pred, average=average_type) # Calculate F1-score
|
|
290
|
+
model_test_precision = precision_score(y_test, y_test_pred, average=average_type) # Calculate Precision
|
|
291
|
+
model_test_recall = recall_score(y_test, y_test_pred, average=average_type) # Calculate Recall
|
|
292
|
+
if average_type == "binary":
|
|
293
|
+
y_test_prob = model.predict_proba(x_test)[:,1]
|
|
294
|
+
model_test_rocauc_score = roc_auc_score(y_test, y_test_prob)
|
|
295
|
+
else:
|
|
296
|
+
y_test_prob=model.predict_proba(x_test)
|
|
297
|
+
model_test_rocauc_score = roc_auc_score(y_test, y_test_prob,multi_class='ovr',average=average_type) #Calculate Roc Auc Score
|
|
270
298
|
|
|
271
299
|
model_dict.append({
|
|
272
300
|
"model":list(models.keys())[i],
|
|
@@ -276,7 +304,6 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
276
304
|
"test_f1": model_test_f1,
|
|
277
305
|
"tuned":False
|
|
278
306
|
})
|
|
279
|
-
model_test_rocauc_score = roc_auc_score(y_test, y_test_pred) #Calculate Roc
|
|
280
307
|
|
|
281
308
|
|
|
282
309
|
# print(list(models.keys())[i])
|
|
@@ -447,7 +474,7 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
447
474
|
["LogisticRegression", {
|
|
448
475
|
'penalty': ['l1', 'l2', 'elasticnet', 'none'],
|
|
449
476
|
'C': np.logspace(-4, 4, 20),
|
|
450
|
-
'solver': ['
|
|
477
|
+
'solver': ['lbfgs', 'liblinear', 'saga'],
|
|
451
478
|
'max_iter': [100, 200, 500, 1000],
|
|
452
479
|
'class_weight': [None, 'balanced'],
|
|
453
480
|
'l1_ratio': [0, 0.25, 0.5, 0.75, 1] # For elasticnet
|
|
@@ -597,7 +624,6 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
597
624
|
for i in range(len(list(models))):
|
|
598
625
|
model = list(models.values())[i]
|
|
599
626
|
model.fit(x_train, y_train) # Train model
|
|
600
|
-
|
|
601
627
|
# Make predictions
|
|
602
628
|
y_train_pred = model.predict(x_train)
|
|
603
629
|
y_test_pred = model.predict(x_test)
|
|
@@ -658,22 +684,38 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
658
684
|
|
|
659
685
|
# Training set performance
|
|
660
686
|
model_train_accuracy = accuracy_score(y_train, y_train_pred) # Calculate Accuracy
|
|
661
|
-
model_train_f1 = f1_score(y_train, y_train_pred, average=
|
|
662
|
-
model_train_precision = precision_score(y_train, y_train_pred) # Calculate Precision
|
|
663
|
-
model_train_recall = recall_score(y_train, y_train_pred) # Calculate Recall
|
|
664
|
-
|
|
687
|
+
model_train_f1 = f1_score(y_train, y_train_pred, average=average_type) # Calculate F1-score
|
|
688
|
+
model_train_precision = precision_score(y_train, y_train_pred,average=average_type) # Calculate Precision
|
|
689
|
+
model_train_recall = recall_score(y_train, y_train_pred,average=average_type) # Calculate Recall
|
|
690
|
+
if average_type == "binary":
|
|
691
|
+
y_train_prob = model.predict_proba(x_train)[:,1]
|
|
692
|
+
model_train_rocauc_score = roc_auc_score(y_train, y_train_prob)
|
|
693
|
+
else:
|
|
694
|
+
y_train_prob=model.predict_proba(x_train)
|
|
695
|
+
model_train_rocauc_score = roc_auc_score(y_train, y_train_prob, multi_class='ovr', average=average_type)
|
|
665
696
|
# Test set performance
|
|
666
697
|
model_test_accuracy = accuracy_score(y_test, y_test_pred) # Calculate Accuracy
|
|
667
|
-
model_test_f1 = f1_score(y_test, y_test_pred, average=
|
|
668
|
-
model_test_precision = precision_score(y_test, y_test_pred) # Calculate Precision
|
|
669
|
-
model_test_recall = recall_score(y_test, y_test_pred) # Calculate
|
|
670
|
-
|
|
698
|
+
model_test_f1 = f1_score(y_test, y_test_pred, average=average_type) # Calculate F1-score
|
|
699
|
+
model_test_precision = precision_score(y_test, y_test_pred,average=average_type) # Calculate Precision
|
|
700
|
+
model_test_recall = recall_score(y_test, y_test_pred,average=average_type) # Calculate Recall
|
|
701
|
+
if average_type == "binary":
|
|
702
|
+
y_test_prob = model.predict_proba(x_test)[:,1]
|
|
703
|
+
model_test_rocauc_score = roc_auc_score(y_test, y_test_prob)
|
|
704
|
+
else:
|
|
705
|
+
y_test_prob=model.predict_proba(x_test)
|
|
706
|
+
model_test_rocauc_score = roc_auc_score(y_test, y_test_prob, multi_class='ovr', average=average_type)
|
|
671
707
|
model_dict={
|
|
672
708
|
"model":list(models.keys())[i],
|
|
673
709
|
"train_accuracy": model_train_accuracy,
|
|
674
710
|
"train_f1": model_train_f1,
|
|
711
|
+
"train_precision": model_train_precision,
|
|
712
|
+
"train_recall": model_train_recall,
|
|
713
|
+
"train_rocauc": model_train_rocauc_score,
|
|
675
714
|
"test_accuracy": model_test_accuracy,
|
|
676
715
|
"test_f1": model_test_f1,
|
|
716
|
+
"test_precision": model_test_precision,
|
|
717
|
+
"test_recall": model_test_recall,
|
|
718
|
+
"test_rocauc": model_test_rocauc_score,
|
|
677
719
|
"tuned":True
|
|
678
720
|
}
|
|
679
721
|
best_models_copy = pd.concat(
|
|
@@ -727,7 +769,7 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
727
769
|
if classification:
|
|
728
770
|
combined_score_ranking=combined_score_ranking[combined_score_ranking["train_f1"]-combined_score_ranking["test_f1"]<0.15]
|
|
729
771
|
# print("====="*35)
|
|
730
|
-
print(combined_score_ranking.iloc[0:1,:])
|
|
772
|
+
# print(combined_score_ranking.iloc[0:1,:])
|
|
731
773
|
best_model_name = combined_score_ranking.iloc[0]["model"]
|
|
732
774
|
best_param_dict = None
|
|
733
775
|
for name, params in best_params:
|
|
@@ -742,36 +784,41 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
742
784
|
print("Saving the model and preprocessor...")
|
|
743
785
|
model_path = os.path.join(artifacts_path, "model.pkl")
|
|
744
786
|
preprocessor_path = os.path.join(artifacts_path, "preprocessor.pkl")
|
|
745
|
-
encoder_path = os.path.join(artifacts_path, "encoder.pkl")
|
|
746
787
|
|
|
747
788
|
with open(model_path, "wb") as f:
|
|
748
789
|
pickle.dump(model, f)
|
|
749
790
|
|
|
750
791
|
with open(preprocessor_path, "wb") as f:
|
|
751
792
|
pickle.dump(preprocessor, f)
|
|
752
|
-
|
|
793
|
+
encoder_path = None
|
|
753
794
|
if classification:
|
|
795
|
+
encoder_path = os.path.join(artifacts_path, "encoder.pkl")
|
|
754
796
|
with open(encoder_path, "wb") as f:
|
|
755
797
|
pickle.dump(le, f)
|
|
756
798
|
response = {
|
|
757
|
-
"
|
|
799
|
+
"Message": "Training completed successfully",
|
|
758
800
|
"Problem_type":"Classification",
|
|
759
|
-
"model_metrics": {
|
|
760
801
|
"Model": combined_score_ranking.iloc[0]["model"],
|
|
761
802
|
"Train_accuracy": float(combined_score_ranking.iloc[0]["train_accuracy"]),
|
|
762
803
|
"Train_f1": float(combined_score_ranking.iloc[0]["train_f1"]),
|
|
804
|
+
"Train_precision": float(combined_score_ranking.iloc[0]["train_precision"]),
|
|
805
|
+
"Train_recall": float(combined_score_ranking.iloc[0]["train_recall"]),
|
|
806
|
+
"Train_rocauc": float(combined_score_ranking.iloc[0]["train_rocauc"]),
|
|
763
807
|
"Test_accuracy": float(combined_score_ranking.iloc[0]["test_accuracy"]),
|
|
764
808
|
"Test_f1": float(combined_score_ranking.iloc[0]["test_f1"]),
|
|
809
|
+
"Test_precision": float(combined_score_ranking.iloc[0]["test_precision"]),
|
|
810
|
+
"Test_recall": float(combined_score_ranking.iloc[0]["test_recall"]),
|
|
811
|
+
"Test_rocauc": float(combined_score_ranking.iloc[0]["test_rocauc"]),
|
|
765
812
|
"Hyper_tuned": bool(combined_score_ranking.iloc[0]["tuned"]),
|
|
766
813
|
"Dropped_Columns":list(dropcorr)
|
|
767
|
-
}
|
|
768
814
|
}
|
|
769
|
-
|
|
815
|
+
if(response["Hyper_tuned"]):
|
|
816
|
+
response["Best_Params"] = best_param_dict
|
|
817
|
+
plot_classification_metrics(model,x_train, y_train, x_test, y_test,plot_path=plot_path)
|
|
770
818
|
else:
|
|
771
819
|
response={
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
"model_metrics": {
|
|
820
|
+
"Message": "Training completed successfully",
|
|
821
|
+
"Problem_type":"Regression",
|
|
775
822
|
"Model": combined_score_ranking.iloc[0]["model"],
|
|
776
823
|
"Train_R2": float(combined_score_ranking.iloc[0]["train_r2"]),
|
|
777
824
|
"Train_RMSE": float(combined_score_ranking.iloc[0]["train_rmse"]),
|
|
@@ -779,10 +826,19 @@ def train_model(data_path, dependent_feature,rmse_prob,f1_prob,n_jobs=-1,n_iter=
|
|
|
779
826
|
"Test_RMSE": float(combined_score_ranking.iloc[0]["test_rmse"]),
|
|
780
827
|
"Hyper_tuned": bool(combined_score_ranking.iloc[0]["tuned"]),
|
|
781
828
|
"Dropped_Columns":list(dropcorr)
|
|
782
|
-
}
|
|
783
829
|
}
|
|
830
|
+
if(response["Hyper_tuned"]):
|
|
831
|
+
response["Best_Params"] = best_param_dict
|
|
784
832
|
plot_regression_metrics(model, x_train, y_train, x_test, y_test,feature_names,plot_path=plot_path)
|
|
785
|
-
print(
|
|
833
|
+
print("\n")
|
|
834
|
+
print("="*55)
|
|
835
|
+
for i in response:
|
|
836
|
+
print(f"{i}: {response[i]}")
|
|
837
|
+
print("="*55)
|
|
838
|
+
print("\n")
|
|
839
|
+
with open(os.path.join(artifacts_path, "metrices.txt"), "w") as f:
|
|
840
|
+
for key, value in response.items():
|
|
841
|
+
f.write(f"{key}: {value}\n")
|
|
786
842
|
print("artifacts_path:", artifacts_path)
|
|
787
843
|
print("model_path:", model_path)
|
|
788
844
|
print("preprocessor_path:", preprocessor_path)
|
|
@@ -794,10 +850,10 @@ def plot_classification_metrics(model, X_train, y_train, X_test, y_test, plot_pa
|
|
|
794
850
|
# Predict
|
|
795
851
|
y_pred = model.predict(X_test)
|
|
796
852
|
y_proba = model.predict_proba(X_test)[:, 1] if hasattr(model, "predict_proba") else None
|
|
797
|
-
|
|
853
|
+
unique_classes = model.classes_
|
|
798
854
|
# Confusion Matrix
|
|
799
855
|
cm = confusion_matrix(y_test, y_pred)
|
|
800
|
-
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=
|
|
856
|
+
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=unique_classes)
|
|
801
857
|
disp.plot(cmap="Blues")
|
|
802
858
|
plt.title("Confusion Matrix")
|
|
803
859
|
plt.savefig(os.path.join(plot_path,"confusion_matrix.png"), bbox_inches='tight')
|
|
@@ -810,14 +866,15 @@ def plot_classification_metrics(model, X_train, y_train, X_test, y_test, plot_pa
|
|
|
810
866
|
plt.savefig(os.path.join(plot_path,"roc_curve.png"), bbox_inches='tight')
|
|
811
867
|
plt.close()
|
|
812
868
|
# Precision-Recall Curve
|
|
813
|
-
if y_proba is not None:
|
|
869
|
+
if y_proba is not None and unique_classes.shape[0] == 2:
|
|
814
870
|
precision, recall, _ = precision_recall_curve(y_test, y_proba)
|
|
815
871
|
PrecisionRecallDisplay(precision=precision, recall=recall).plot()
|
|
816
872
|
plt.title("Precision-Recall Curve")
|
|
817
873
|
plt.savefig(os.path.join(plot_path,"precision_recall_curve.png"), bbox_inches='tight')
|
|
818
874
|
plt.close()
|
|
819
875
|
# Learning Curve
|
|
820
|
-
|
|
876
|
+
cv = min(5, np.min(np.bincount(y_train)))
|
|
877
|
+
train_sizes, train_scores, val_scores = learning_curve(model, X_train, y_train, cv=cv, scoring='accuracy')
|
|
821
878
|
plt.plot(train_sizes, np.mean(train_scores, axis=1), label="Train")
|
|
822
879
|
plt.plot(train_sizes, np.mean(val_scores, axis=1), label="Validation")
|
|
823
880
|
plt.title("Learning Curve (Accuracy)")
|
|
@@ -835,6 +892,9 @@ def plot_classification_metrics(model, X_train, y_train, X_test, y_test, plot_pa
|
|
|
835
892
|
ax[1].set_title("Testing Class Distribution")
|
|
836
893
|
plt.savefig(os.path.join(plot_path,"class_distribution.png"), bbox_inches='tight')
|
|
837
894
|
plt.close()
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
838
898
|
def plot_regression_metrics(model, X_train, y_train, X_test, y_test,feature_names,plot_path):
|
|
839
899
|
y_pred = model.predict(X_test)
|
|
840
900
|
residuals = y_test - y_pred
|
|
@@ -876,13 +936,12 @@ def plot_regression_metrics(model, X_train, y_train, X_test, y_test,feature_name
|
|
|
876
936
|
def main():
|
|
877
937
|
import argparse
|
|
878
938
|
parser = argparse.ArgumentParser()
|
|
879
|
-
parser.add_argument("--data_path", required=True)
|
|
880
|
-
parser.add_argument("--dependent_feature", required=True)
|
|
881
|
-
parser.add_argument("--rmse_prob", required=True)
|
|
882
|
-
parser.add_argument("--f1_prob", required=True)
|
|
883
|
-
parser.add_argument("--n_jobs", default=-1, type=int)
|
|
884
|
-
parser.add_argument("--n_iter", default=100, type=int)
|
|
885
|
-
parser.add_argument("--cv", default=3, type=int)
|
|
939
|
+
parser.add_argument("--data_path", required=True,help="Path to the dataset CSV file")
|
|
940
|
+
parser.add_argument("--dependent_feature", required=True,help="Name of the dependent feature (target variable)")
|
|
941
|
+
parser.add_argument("--rmse_prob", required=True,help="RMSE probability threshold")
|
|
942
|
+
parser.add_argument("--f1_prob", required=True,help="F1 score probability threshold")
|
|
943
|
+
parser.add_argument("--n_jobs", default=-1, type=int,help="Number of jobs to run in parallel")
|
|
944
|
+
parser.add_argument("--n_iter", default=100, type=int,help="Number of iterations for hyperparameter tuning")
|
|
945
|
+
parser.add_argument("--cv", default=3, type=int,help="Number of cross-validation folds")
|
|
886
946
|
args = parser.parse_args()
|
|
887
947
|
print(train_model(args.data_path, args.dependent_feature, rmse_prob=args.rmse_prob, f1_prob=args.f1_prob, n_jobs=args.n_jobs, n_iter=args.n_iter, cv=args.cv))
|
|
888
|
-
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mlforgex
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Lightweight ML utility for automated training, evaluation, and prediction with CLI and Python API support
|
|
5
|
-
Home-page: https://github.com/yourusername/mlforge
|
|
6
5
|
Author: Priyanshu Mathur
|
|
7
6
|
Author-email: mathurpriyanshu2006@gmail.com
|
|
8
7
|
License: MIT
|
|
@@ -24,14 +23,13 @@ Dynamic: author-email
|
|
|
24
23
|
Dynamic: classifier
|
|
25
24
|
Dynamic: description
|
|
26
25
|
Dynamic: description-content-type
|
|
27
|
-
Dynamic: home-page
|
|
28
26
|
Dynamic: license
|
|
29
27
|
Dynamic: license-file
|
|
30
28
|
Dynamic: requires-dist
|
|
31
29
|
Dynamic: requires-python
|
|
32
30
|
Dynamic: summary
|
|
33
31
|
|
|
34
|
-
# mlforgex
|
|
32
|
+
# mlforgex [](https://pepy.tech/projects/mlforgex)
|
|
35
33
|
|
|
36
34
|
**mlforgex** is a Python package that enables easy training, evaluation, and prediction for machine learning models on cleaned dataset. It supports both classification and regression problems, automates preprocessing, model selection, hyperparameter tuning, and generates useful artifacts and plots for analysis.
|
|
37
35
|
|
|
@@ -5,7 +5,7 @@ this_directory = Path(__file__).parent
|
|
|
5
5
|
long_description = (this_directory / "README.md").read_text()
|
|
6
6
|
setup(
|
|
7
7
|
name="mlforgex",
|
|
8
|
-
version="1.0.
|
|
8
|
+
version="1.0.4",
|
|
9
9
|
packages=find_packages(),
|
|
10
10
|
install_requires = [
|
|
11
11
|
"pandas",
|
|
@@ -28,7 +28,6 @@ setup(
|
|
|
28
28
|
author="Priyanshu Mathur",
|
|
29
29
|
author_email="mathurpriyanshu2006@gmail.com",
|
|
30
30
|
description="Lightweight ML utility for automated training, evaluation, and prediction with CLI and Python API support",
|
|
31
|
-
url="https://github.com/yourusername/mlforge",
|
|
32
31
|
license="MIT",
|
|
33
32
|
classifiers=[
|
|
34
33
|
"License :: OSI Approved :: MIT License",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from mlforge import train_model, predict
|
|
2
|
+
|
|
3
|
+
def test_train_model():
|
|
4
|
+
result = train_model("StudentsPerformance.csv", "math_score", rmse_prob=0.3, f1_prob=0.7, n_jobs=-1)
|
|
5
|
+
assert result["status"] == "success"
|
|
6
|
+
|
|
7
|
+
def test_predict():
|
|
8
|
+
result =predict("artifacts/model.pkl", "artifacts/preprocessor.pkl", "input.csv")
|
|
9
|
+
assert "prediction" in result
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import pickle;
|
|
2
|
-
import pandas as pd;
|
|
3
|
-
def predict(model_path,preprocessor_path,input_data, encoder_path=None):
|
|
4
|
-
print("Loading the pickled model and preprocessor...")
|
|
5
|
-
model = pickle.load(open(model_path, 'rb'))
|
|
6
|
-
preprocessor = pickle.load(open(preprocessor_path, 'rb'))
|
|
7
|
-
encoder = pickle.load(open(encoder_path, 'rb')) if encoder_path else None
|
|
8
|
-
df= pd.read_csv(input_data)
|
|
9
|
-
X = preprocessor.transform(df)
|
|
10
|
-
predictions = model.predict(X)
|
|
11
|
-
if encoder_path:
|
|
12
|
-
predictions = encoder.inverse_transform(predictions)
|
|
13
|
-
return {"prediction": predictions.tolist()}
|
|
14
|
-
def main():
|
|
15
|
-
import argparse
|
|
16
|
-
parser = argparse.ArgumentParser()
|
|
17
|
-
parser.add_argument("--model_path", required=True)
|
|
18
|
-
parser.add_argument("--input_data", required=True)
|
|
19
|
-
parser.add_argument("--preprocessor_path", required=True)
|
|
20
|
-
parser.add_argument("--encoder_path", required=False)
|
|
21
|
-
args = parser.parse_args()
|
|
22
|
-
print(predict(args.model_path, args.preprocessor_path, args.input_data, args.encoder_path))
|
|
23
|
-
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
from mlforge import train_model, predict
|
|
2
|
-
|
|
3
|
-
def test_train_model():
|
|
4
|
-
result = train_model("mlforge/diabetes_cleaned.csv", "Outcome", rmse_prob=0.3, f1_prob=0.7, n_jobs=-1)
|
|
5
|
-
assert result["status"] == "success"
|
|
6
|
-
|
|
7
|
-
def test_predict():
|
|
8
|
-
result =predict("mlforge/artifacts/model.pkl", "mlforge/artifacts/preprocessor.pkl", "mlforge/input.csv", "mlforge/artifacts/encoder.pkl")
|
|
9
|
-
assert "prediction" in result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|