From 2e8f3bdb1935cad5ab397f88b7762d7209637dc9 Mon Sep 17 00:00:00 2001 From: Marcellin Date: Thu, 28 Nov 2024 15:54:37 +0100 Subject: [PATCH] Add files via upload --- credit-card-fraud-detection-1-638.jpg | Bin 0 -> 44945 bytes evaluation_report.md | 60 ++++++++++++++++++++ main.py | 49 ++++++++++++++++ requirements.txt | 4 ++ src/__pycache__/data_loader.cpython-312.pyc | Bin 0 -> 1345 bytes src/__pycache__/evaluate.cpython-312.pyc | Bin 0 -> 2374 bytes src/__pycache__/model.cpython-312.pyc | Bin 0 -> 1987 bytes src/__pycache__/preprocess.cpython-312.pyc | Bin 0 -> 1592 bytes src/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2209 bytes src/data_loader.py | 31 ++++++++++ src/evaluate.py | 59 +++++++++++++++++++ src/model.py | 52 +++++++++++++++++ src/preprocess.py | 46 +++++++++++++++ src/utils.py | 48 ++++++++++++++++ 14 files changed, 349 insertions(+) create mode 100644 credit-card-fraud-detection-1-638.jpg create mode 100644 evaluation_report.md create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 src/__pycache__/data_loader.cpython-312.pyc create mode 100644 src/__pycache__/evaluate.cpython-312.pyc create mode 100644 src/__pycache__/model.cpython-312.pyc create mode 100644 src/__pycache__/preprocess.cpython-312.pyc create mode 100644 src/__pycache__/utils.cpython-312.pyc create mode 100644 src/data_loader.py create mode 100644 src/evaluate.py create mode 100644 src/model.py create mode 100644 src/preprocess.py create mode 100644 src/utils.py diff --git a/credit-card-fraud-detection-1-638.jpg b/credit-card-fraud-detection-1-638.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44626fee9068ef4dd66fe1bb1c35478686905136 GIT binary patch literal 44945 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 literal 0 HcmV?d00001 diff --git a/src/__pycache__/model.cpython-312.pyc b/src/__pycache__/model.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..531b16af361be43bfcbf0fe824a564bee8c651de GIT binary patch literal 1987 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 RCP{eaTtufE{|K&B@E_@lXH@_I literal 0 HcmV?d00001 diff --git a/src/data_loader.py b/src/data_loader.py new file mode 100644 index 0000000..3b4e38c --- /dev/null +++ b/src/data_loader.py @@ -0,0 +1,31 @@ +import pandas as pd + +def load_data(file_path, **kwargs): + """ + Load dataset from a specified file path. + + Parameters: + ---------- + file_path : str + Path to the CSV file. + **kwargs : dict + Additional keyword arguments for pandas.read_csv. + + Returns: + ------- + pd.DataFrame + Loaded dataset as a Pandas DataFrame. + """ + try: + data = pd.read_csv(file_path, **kwargs) + print(f"Data successfully loaded from {file_path}. Shape: {data.shape}") + return data + except FileNotFoundError: + print(f"Error: File not found at {file_path}.") + raise + except pd.errors.EmptyDataError: + print(f"Error: No data found in file at {file_path}.") + raise + except Exception as e: + print(f"An error occurred while loading the data: {e}") + raise diff --git a/src/evaluate.py b/src/evaluate.py new file mode 100644 index 0000000..e8a0a01 --- /dev/null +++ b/src/evaluate.py @@ -0,0 +1,59 @@ +from sklearn.metrics import accuracy_score, classification_report, confusion_matrix + +def evaluate_model(model, X_test, y_test, output_path=None): + """ + Evaluate the model and return performance metrics. + + Parameters: + ---------- + model : sklearn.base.BaseEstimator + The trained model to evaluate. + X_test : pd.DataFrame or np.ndarray + The testing feature set. + y_test : pd.Series or np.ndarray + The true labels for the test set. + output_path : str, optional + Path to save the evaluation report. Default is None. + + Returns: + ------- + dict + A dictionary containing accuracy, classification report, and confusion matrix. + + Raises: + ------ + NotFittedError + If the model is not fitted before evaluation. + """ + try: + # Generate predictions + predictions = model.predict(X_test) + + # Calculate metrics + acc = accuracy_score(y_test, predictions) + report = classification_report(y_test, predictions, output_dict=True) + conf_matrix = confusion_matrix(y_test, predictions) + + # Compile evaluation results + evaluation_results = { + "accuracy": acc, + "classification_report": report, + "confusion_matrix": conf_matrix.tolist() + } + + # Optional: Save evaluation report as a file + if output_path: + with open(output_path, 'w') as f: + f.write("Accuracy: {:.4f}\n".format(acc)) + f.write("\nClassification Report:\n") + f.write(classification_report(y_test, predictions)) + f.write("\nConfusion Matrix:\n") + f.write(str(conf_matrix)) + print(f"Evaluation report saved to {output_path}.") + + print(f"Model evaluation completed. Accuracy: {acc:.4f}") + return evaluation_results + + except Exception as e: + print(f"An error occurred during model evaluation: {e}") + raise diff --git a/src/model.py b/src/model.py new file mode 100644 index 0000000..194f00a --- /dev/null +++ b/src/model.py @@ -0,0 +1,52 @@ +from sklearn.linear_model import LogisticRegression +from sklearn.ensemble import RandomForestClassifier +from sklearn.exceptions import NotFittedError + +def train_model(X_train, y_train, model_type='logistic', **kwargs): + """ + Train a model with the specified type. + + Parameters: + ---------- + X_train : pd.DataFrame or np.ndarray + The training feature set. + y_train : pd.Series or np.ndarray + The training target labels. + model_type : str, optional + The type of model to train ('logistic' or 'random_forest'). + Default is 'logistic'. + **kwargs : dict + Additional keyword arguments to pass to the model constructor. + + Returns: + ------- + model : sklearn.base.BaseEstimator + The trained model. + + Raises: + ------ + ValueError + If an unsupported model type is provided. + """ + try: + if model_type == 'logistic': + model = LogisticRegression(**kwargs) + elif model_type == 'random_forest': + model = RandomForestClassifier(**kwargs) + else: + raise ValueError(f"Unsupported model type: {model_type}") + + # Train the model + model.fit(X_train, y_train) + print(f"Model of type '{model_type}' trained successfully.") + return model + + except ValueError as ve: + print(f"ValueError: {ve}") + raise + except NotFittedError as nfe: + print(f"Model fitting failed: {nfe}") + raise + except Exception as e: + print(f"An unexpected error occurred during model training: {e}") + raise diff --git a/src/preprocess.py b/src/preprocess.py new file mode 100644 index 0000000..eeb542e --- /dev/null +++ b/src/preprocess.py @@ -0,0 +1,46 @@ +import pandas as pd +from sklearn.preprocessing import StandardScaler + +def preprocess_data(df, output_path=None): + """ + Preprocess the data, including scaling and handling missing values. + + Parameters: + ---------- + df : pd.DataFrame + The input dataset to preprocess. + output_path : str, optional + Path to save the processed DataFrame as a CSV file. Default is None. + + Returns: + ------- + pd.DataFrame + The preprocessed DataFrame. + """ + # Handle duplicates + df = df.drop_duplicates() + + # Drop unnecessary columns + if 'Time' in df.columns: + df = df.drop("Time", axis=1) + + # Scale the 'Amount' column + scaler = StandardScaler() + if 'Amount' in df.columns: + df["Amount"] = scaler.fit_transform(df[["Amount"]]) + else: + raise KeyError("Column 'Amount' not found in the DataFrame.") + + #Oversampling + + + # Save the processed data if an output path is provided + if output_path: + try: + df.to_csv(output_path, index=False) + print(f"Processed data successfully saved to {output_path}.") + except Exception as e: + print(f"Failed to save processed data: {e}") + raise + + return df diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..fac5b35 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,48 @@ +import numpy as np +from sklearn.model_selection import train_test_split +import pandas as pd +from imblearn.over_sampling import SMOTE + +def split_data(df: pd.DataFrame, target_column: str, test_size: float = 0.2, random_state: int = 42) -> tuple: + """ + Split data into training and testing sets. + + Parameters: + ---------- + df : pd.DataFrame + The input DataFrame containing features and target. + target_column : str + The name of the target column to predict. + test_size : float, optional + The proportion of the dataset to include in the test split. Default is 0.2. + random_state : int, optional + The random seed for reproducibility. Default is 42. + + Returns: + ------- + tuple + Four objects: X_train, X_test, y_train, y_test. + + Raises: + ------ + KeyError + If the target column is not found in the DataFrame. + ValueError + If the DataFrame is empty. + """ + if df.empty: + raise ValueError("The input DataFrame is empty.") + + if target_column not in df.columns: + raise KeyError(f"The target column '{target_column}' is not found in the DataFrame.") + + # Splitting the data + X = df.drop(columns=[target_column]) + y = df[target_column] + + X_res, y_res = SMOTE().fit_resample(X,y) + + X_train, X_test, y_train, y_test = train_test_split(X_res, y_res, test_size=test_size, random_state=random_state) + + print(f"Data split completed: Train set - {X_train.shape[0]} samples, Test set - {X_test.shape[0]} samples.") + return X_train, X_test, y_train, y_test