Skip to content

Repository files navigation

banner

๐ŸŽฏ Objective

The purpose of this project is to demonstrate complete, practical knowledge of Data Preprocessing and Feature Engineering โ€” walking the full end-to-end path from raw, messy, multi-source data to a single clean, consistent, model-ready dataset.

Every stage is deliberate: understand โ†’ clean โ†’ impute โ†’ treat outliers โ†’ encode โ†’ scale โ†’ transform โ†’ construct. Nothing is skipped, and every technique is followed by a ๐ŸŽฏ Insights note explaining what it did to the data and whether it was the right call.


๐Ÿ“„ Problem Statement

You are hired as a Junior Data Scientist at a fintech company. The company provides a Customer Credit Risk dataset collected from multiple sources โ€” CSV files, JSON files, SQL tables, and an external API. Your manager asks you to perform full-scale preprocessing and feature engineering so the dataset becomes clean, consistent, and suitable for building a Machine Learning model that predicts whether a customer will default on a loan.

The dataset contains:

  • Demographics โ€” age, gender, region, education level, employment type.
  • Financial details โ€” annual income, loan amount, loan purpose, repayment history, credit score.
  • Behavioural attributes โ€” transactions, spending habits, missed payments.
  • Target variable โ€” Loan Default โ†’ 0 (No), 1 (Yes).

๐Ÿ“‚ Project Files

๐Ÿ“„ File / Folder ๐Ÿ“Œ Description
๐Ÿ““ Holistic_Data_Preparer.ipynb Main notebook โ€” the complete, annotated preprocessing & feature-engineering pipeline
๐Ÿ“Š customer_credit_risk_main_transactions_1000.csv Raw core transactions dataset (CSV source)
๐Ÿ“‘ customer_metadata_1000.json Customer metadata (JSON source)
๐Ÿ—„๏ธ loan_repayment_history.db SQLite database with loan repayment history (SQL source)
๐Ÿ“ˆ customer_credit_risk_data_quality_report.html Auto-generated Pandas/ydata profiling report
๐Ÿงผ final_processed_dataset.csv Final cleaned, encoded and scaled ML-ready dataset
๐Ÿ“‚ theory_concepts.pdf PDF of theory concepts
๐Ÿ“˜ README.md Project documentation and workflow guide

๐Ÿ› ๏ธ Tools Used


๐ŸŽฌ Project Demo

Watch Demo

๐Ÿ“น Click the badge above to watch the complete project demonstration.


๐Ÿงฌ Dataset Structure โ€” Customer Credit Risk

Field Name Data Type Description Notes
customer_id String / Int Unique identifier for each customer Join key โ€” no missing values
age Integer Age of customer (years) Missing values injected
gender Categorical Male / Female / Other Missing + category imbalance
region Categorical North / South / East / West One-Hot Encoding
education_level Ordinal Cat. Primary / Secondary / Graduate / Post-Graduate Ordinal Encoding
employment_type Categorical Salaried / Self-Employed / Unemployed Categorical imputation
annual_income Float Annual income (โ‚น) Very high outliers + missing
loan_amount Float Loan amount requested (โ‚น) Outliers + skewed distribution
loan_purpose Categorical Home / Car / Education / Business / Other One-Hot Encoding
credit_score Float Credit score (300โ€“850) Outliers + missing values
repayment_history Integer Missed payments in last 12 months Binning / outlier treatment
transaction_count Integer Transactions in last 6 months K-Means / Quantile binning
spending_ratio Float Spending-to-income ratio (%) Log / Box-Cox / Yeo-Johnson
join_date Date Date customer joined the bank Extract Y / M / D / Weekday
default_flag Binary Int 0 = No Default, 1 = Default ๐ŸŽฏ ML target

3ae12da8-4deb-428a-906d-0fb3b7fc96b3

๐Ÿ“ฅ Part B : Data Acquisition

partB

3๏ธโƒฃ Import datasets from multiple sources

๐Ÿ“‚ Load CSV files (main transactions dataset)
transactions_df = pd.read_csv("customer_credit_risk_main_transactions_1000.csv")
transactions_df.head()

๐Ÿ’ก Insight: The CSV is the core fact table โ€” 1000 customers with demographics, financials and the default_flag target. Everything else joins onto it. ๐Ÿ“Š


๐Ÿ“‘ Parse JSON files (customer metadata)
metadata_df = pd.read_json("customer_metadata_1000.json")
metadata_df.head()

๐Ÿ’ก Insight: JSON adds contextual metadata such as join_date and spending_ratio, keyed by customer_id โ€” proving the pipeline can absorb semi-structured sources, not just flat files. ๐Ÿงพ


๐Ÿ—„๏ธ Fetch records from SQL
conn = sqlite3.connect("loan_repayment_history.db")
repayment_df = pd.read_sql_query("SELECT * FROM loan_repayment_history", conn)
conn.close()

print(repayment_df.isna().sum())
repayment_df.head()

๐Ÿ’ก Insight: The SQL table carries behavioural signals (repayment_history, transaction_count) and deliberately injected NULLs โ€” the perfect proving ground for the imputation section that follows. ๐Ÿ—ƒ๏ธ


๐ŸŒ Fetch data from an API (external economic indicators)
url = "https://api.worldbank.org/v2/country/IND/indicator/FP.CPI.TOTL.ZG?format=json"
data = requests.get(url).json()[1]

api_df = pd.DataFrame(data)[['country', 'date', 'value']]
api_df.columns = ['country', 'year', 'inflation_rate']
api_df.head()

๐Ÿ’ก Insight: Live inflation-rate data from the World Bank adds macro-economic context that no internal table can provide โ€” real credit-risk models are always enriched with external indicators. ๐ŸŒ


๐Ÿ”— Merge CSV + JSON + SQL
final_df = (
    transactions_df
    .merge(metadata_df,  on="customer_id", how="left")
    .merge(repayment_df, on="customer_id", how="left")
)
print(final_df.shape)
final_df.head()

๐Ÿ’ก Insight: Three heterogeneous sources collapse into one analytical base table keyed on customer_id. how="left" guarantees no customer is lost, and any unmatched key simply surfaces as a missing value โ€” handled next. ๐Ÿงฉ


๐Ÿงน Part C : Data Understanding & Cleaning

partC

4๏ธโƒฃ Explore the dataset using pandas

final_df.info()
final_df.describe()

print("---------All Missing Values---------")
final_df.isnull().sum()

๐Ÿ’ก Insight: .info() exposes dtypes and non-null counts, .describe() exposes the wild spread in annual_income and loan_amount (huge max vs median = outliers ahead). Missing values are scattered but never dominant, so no column needs dropping. ๐Ÿ”


5๏ธโƒฃ Pandas Profiling โ€” data quality report

profile = ProfileReport(
    final_df,
    title="Customer Credit Risk Data Quality Report",
    explorative=True
)
profile.to_file("customer_credit_risk_data_quality_report.html")

๐Ÿ’ก Insight: One command produces a complete HTML audit โ€” distributions, correlations, missing-value matrix, duplicate check and warnings. It turns hours of manual EDA into a single reproducible artefact. ๐Ÿ“ˆ


๐Ÿงฉ Handle missing data with :-

๐Ÿ“‹ Simple Imputer (Numerical: Mean / Median)
mean_df = final_df.copy()

num_cols = ["age", "annual_income", "loan_amount", "credit_score",
            "spending_ratio", "repayment_history", "transaction_count"]

mean_imputer = SimpleImputer(strategy="mean")
mean_df[num_cols] = mean_imputer.fit_transform(mean_df[num_cols])

print(mean_df[num_cols].isnull().sum())

๐Ÿ’ก Insight: Mean imputation fills every numeric gap โ€” the post-imputation null count is 0 for all numeric columns. It is fast and keeps the mean unchanged, but it shrinks variance and distorts skewed columns like annual_income. โš–๏ธ


๐Ÿท๏ธ Simple Imputer (Categorical: Most Frequent)
cat_cols = ["gender", "employment_type"]

cat_imputed_df = final_df.copy()
cat_imputer = SimpleImputer(strategy="most_frequent")
cat_imputed_df[cat_cols] = cat_imputer.fit_transform(cat_imputed_df[cat_cols])

print(cat_imputed_df[cat_cols].isnull().sum())

๐Ÿ’ก Insight: Mean/median can't apply to text โ€” the mode keeps imputed categories realistic and avoids inventing a meaningless new class. Being sklearn-based, it drops straight into a ColumnTransformer. ๐Ÿ‘ฅ


๐Ÿ“Š Most Frequent Category Imputation (pandas equivalent)
mfci_df = final_df.copy()

for col in cat_cols:
    mfci_df[col] = mfci_df[col].fillna(mfci_df[col].mode()[0])

print(mfci_df[cat_cols].isnull().sum())

๐Ÿ’ก Insight: The manual mode() fill reproduces the sklearn result exactly โ€” pandas gives per-column transparency, sklearn gives pipeline reusability. Same answer, different ergonomics. ๐Ÿ”


๐Ÿ” Missing Indicator + Random Sample Imputation
random_sample_df = final_df.copy()
random_sample_df["annual_income_missing"] = random_sample_df["annual_income"].isnull().astype(int)

random_values = random_sample_df["annual_income"].dropna().sample(
    random_sample_df["annual_income"].isnull().sum(),
    random_state=42, replace=True
)
random_sample_df.loc[random_sample_df["annual_income"].isnull(), "annual_income"] = random_values.values

๐Ÿ’ก Insight: Random sampling draws from the observed distribution, so skew and variance survive intact โ€” unlike mean imputation, which flattens them. The annual_income_missing flag lets the model learn whether missingness itself carries signal. ๐Ÿšฉ


โšก KNN Imputer (multivariate)
knn_df = final_df.copy()
knn = KNNImputer(n_neighbors=5)
knn_df[num_cols] = knn.fit_transform(knn_df[num_cols])
knn_df[num_cols].describe()

๐Ÿ’ก Insight: KNN fills each gap using the five most similar customers, capturing multivariate relationships (income โ†” loan amount โ†” credit score) that univariate methods ignore. Costlier, but distribution-faithful. ๐Ÿค


โ™ป๏ธ MICE Algorithm (chained equations)
mice_df = final_df.copy()
mice = IterativeImputer(random_state=42)
mice_df[num_cols] = mice.fit_transform(mice_df[num_cols])

๐Ÿ’ก Insight: MICE models each column as a regression on all the others and iterates until convergence โ€” statistically the most robust estimator here, and the method chosen for the final numeric imputation. ๐Ÿ”ฌ


๐Ÿ—‘๏ธ Complete Case Analysis
cca_df = final_df.dropna()
print("Before:", final_df.shape, " After:", cca_df.shape)

๐Ÿ’ก Insight: Dropping incomplete rows is the simplest option but the most expensive โ€” a meaningful share of customers disappears, and any bias in why data was missing is baked in. Useful as a baseline, not a solution. โš ๏ธ


โš ๏ธ Part D : Outlier Handling

partD

7๏ธโƒฃ Detect and treat outliers using:

๐Ÿ“ˆ Z-score Method
zscore_df = final_df.copy()
num_cols = ["annual_income", "loan_amount", "credit_score",
            "repayment_history", "transaction_count"]

z_scores = np.abs(zscore(zscore_df[num_cols], nan_policy="omit"))
print(pd.DataFrame(z_scores > 3, columns=num_cols).sum())

zscore_df = zscore_df[(z_scores < 3).all(axis=1)]
print("Original:", final_df.shape, " After:", zscore_df.shape)

๐Ÿ’ก Insight: The |z| > 3 rule flags a small set of extremes, mostly in annual_income and loan_amount. Because it depends on the mean and std โ€” both of which outliers inflate โ€” it is itself sensitive to outliers and assumes near-normality. ๐Ÿ“


๐Ÿ“‰ IQR Method
iqr_df = final_df.copy()

for col in num_cols:
    Q1, Q3 = iqr_df[col].quantile(0.25), iqr_df[col].quantile(0.75)
    IQR = Q3 - Q1
    lower, upper = Q1 - 1.5 * IQR, Q3 + 1.5 * IQR
    iqr_df = iqr_df[(iqr_df[col] >= lower) & (iqr_df[col] <= upper)]

print("Shape after IQR filtering:", iqr_df.shape)

๐Ÿ’ก Insight: Quartile-based and therefore robust to skew, IQR flags noticeably more rows than Z-score. repayment_history and transaction_count are near-uniform, so most removals come from the monetary columns. ๐Ÿงฎ


๐Ÿ’ก Percentile Method
percentile_df = final_df.copy()

for col in num_cols:
    lower, upper = percentile_df[col].quantile(0.01), percentile_df[col].quantile(0.99)
    percentile_df = percentile_df[(percentile_df[col] >= lower) & (percentile_df[col] <= upper)]

print("Shape after trimming:", percentile_df.shape)

๐Ÿ’ก Insight: Trimming at the 1st/99th percentile gives explicit control over how much data is dropped rather than letting the statistics decide โ€” a predictable, auditable rule. ๐ŸŽฏ


โœ‚๏ธ Winsorization Technique
winsor_df = final_df.copy()

for col in num_cols:
    lower, upper = winsor_df[col].quantile(0.05), winsor_df[col].quantile(0.95)
    winsor_df[col] = winsor_df[col].clip(lower, upper)

print("Winsorization Applied Successfully!")

๐Ÿ’ก Insight: Capping at the 5th/95th percentile retains all 1000 customers while pulling minima and maxima inward. Extremes stop dominating scalers and distance-based models โ€” the best quality/quantity trade-off in this project. ๐ŸงŠ


๐Ÿงฌ Part E : Feature Engineering

partE

8๏ธโƒฃ Handle variable types

๐Ÿ”„ Mixed Variables (numeric + categorical)
numerical_cols   = final_df.select_dtypes(include=["int64", "float64"]).columns
categorical_cols = final_df.select_dtypes(include=["object"]).columns

print("Numerical:", list(numerical_cols))
print("Categorical:", list(categorical_cols))

๐Ÿ’ก Insight: A clean dtype split is the foundation of every ColumnTransformer that follows โ€” numeric columns get scaled, categorical columns get encoded, and nothing is mistakenly processed twice. ๐Ÿงท


๐Ÿ“… Date & Time variables โ†’ Year, Month, Day, Weekday
final_df["join_date"]    = pd.to_datetime(final_df["join_date"])
final_df["join_year"]    = final_df["join_date"].dt.year
final_df["join_month"]   = final_df["join_date"].dt.month
final_df["join_day"]     = final_df["join_date"].dt.day
final_df["join_weekday"] = final_df["join_date"].dt.day_name()

๐Ÿ’ก Insight: One opaque timestamp becomes four usable features, unlocking tenure, seasonality and weekday effects that a raw date string could never express. ๐Ÿ“†


9๏ธโƒฃ Encoding categorical variables

๐Ÿ”  Ordinal Encoding (education levels)
education_order = {"Primary": 0, "Secondary": 1, "Graduate": 2, "Post-Graduate": 3}
ordinal_df = final_df.copy()
ordinal_df["education_level"] = ordinal_df["education_level"].map(education_order)

๐Ÿ’ก Insight: Education has a true ranking, so mapping to 0โ€“3 preserves real information the model can exploit. Using one-hot here would throw that ordering away. ๐ŸŽ“


๐Ÿ”  Label Encoding (binary features)
label_df = final_df.copy()
label_encoder = LabelEncoder()
label_df["gender"] = label_encoder.fit_transform(label_df["gender"])

print(dict(zip(label_encoder.classes_, label_encoder.transform(label_encoder.classes_))))

๐Ÿ’ก Insight: Compact integer codes for a low-cardinality field, with the printed mapping documenting exactly which class became which code โ€” essential for reproducibility and interpretation. ๐Ÿท๏ธ


๐Ÿ”  One-Hot Encoding (regions, loan purpose)
onehot_df = pd.get_dummies(final_df, columns=["region", "loan_purpose"], dtype=int)
onehot_df.filter(regex="region_|loan_purpose_").head()

๐Ÿ’ก Insight: region and loan_purpose are nominal โ€” no natural order exists. One-hot expands them into indicator columns so the model never infers a fake ranking like Home < Car < Education. ๐Ÿ—บ๏ธ


๐Ÿ”Ÿ Encoding numerical features

๐Ÿ“ถ Binning (discretize income into groups)
binning_df = final_df.copy()
binning_df["income_group"] = pd.cut(binning_df["annual_income"], bins=3,
                                    labels=["Low", "Medium", "High"])
binning_df["income_group"].value_counts()

๐Ÿ’ก Insight: Equal-width bins are easy to read but produce unbalanced groups on skewed income โ€” a direct consequence of splitting by range rather than by count. ๐Ÿ“ฆ


๐Ÿ“ถ Binarization (flag if > threshold)
binarization_df = final_df.copy()
binarization_df["credit_score"] = binarization_df["credit_score"].fillna(
    binarization_df["credit_score"].median())

binarizer = Binarizer(threshold=700)
binarization_df["credit_score_flag"] = binarizer.fit_transform(
    binarization_df[["credit_score"]]).astype(int)

๐Ÿ’ก Insight: A crisp credit_score_flag separates prime from sub-prime customers in a single interpretable column โ€” exactly the kind of feature a risk officer can reason about. ๐ŸŽš๏ธ


๐Ÿ“ถ Quantile Binning
quantile_df = final_df.copy()
quantile_df["transaction_count_quantile"] = pd.qcut(
    quantile_df["transaction_count"], q=4, labels=["Q1", "Q2", "Q3", "Q4"])

๐Ÿ’ก Insight: Unlike equal-width binning, quantile binning guarantees equally populated buckets, which keeps every group statistically meaningful. ๐Ÿ“


๐Ÿ“ถ K-Means Binning
kmeans_df = final_df.copy()
kbins = KBinsDiscretizer(n_bins=4, encode="ordinal", strategy="kmeans")
kmeans_df["transaction_count_kmeans"] = kbins.fit_transform(
    kmeans_df[["transaction_count"]]).astype(int)

๐Ÿ’ก Insight: K-Means places cut points where the data naturally clusters rather than at arbitrary widths or counts โ€” the most data-driven of the three binning strategies. ๐Ÿง 


๐Ÿ“ Part F : Feature Scaling

partF

1๏ธโƒฃ1๏ธโƒฃ Apply multiple scaling methods

scale_cols = ["annual_income", "loan_amount", "credit_score", "spending_ratio"]

standard = StandardScaler().fit_transform(final_df[scale_cols])   # Z-score
normal   = Normalizer().fit_transform(final_df[scale_cols])       # unit norm
minmax   = MinMaxScaler().fit_transform(final_df[scale_cols])     # 0โ€“1
maxabs   = MaxAbsScaler().fit_transform(final_df[scale_cols])     # โˆ’1โ€“1
robust   = RobustScaler().fit_transform(final_df[scale_cols])     # median / IQR
Scaler What it does Best for
๐Ÿ“ Standardization mean 0, std 1 Linear models, PCA, SVM
๐Ÿ“ Normalization scales each row to unit norm Distance/similarity models
๐Ÿ“Š Min-Max squeezes into 0โ€“1 Neural networks, bounded inputs
โž• MaxAbs scales by max magnitude Sparse data, keeps zeros
๐Ÿ›ก๏ธ Robust centres on median, scales by IQR Outlier-heavy money columns

๐Ÿ’ก Insight: Because annual_income and loan_amount carry heavy tails even after treatment, Robust Scaling is the most trustworthy choice โ€” it ignores the tails entirely by using median and IQR instead of mean and std. ๐Ÿ›ก๏ธ


๐Ÿง  Part G : Feature Construction & Transformation

partG

1๏ธโƒฃ2๏ธโƒฃ Apply transformations

๐Ÿ”ง FunctionTransformer โ†’ log, reciprocal, square root
log_tf  = FunctionTransformer(np.log1p, validate=True)
sqrt_tf = FunctionTransformer(np.sqrt,  validate=True)

final_df["spending_ratio_log"]  = log_tf.fit_transform(final_df[["spending_ratio"]])
final_df["spending_ratio_sqrt"] = sqrt_tf.fit_transform(final_df[["spending_ratio"]])

๐Ÿ’ก Insight: log1p compresses the long right tail of spending_ratio into a far more symmetric shape (and safely handles zeros), while sqrt gives a gentler correction for mild skew. ๐Ÿ“‰


โšก PowerTransformer โ†’ Box-Cox & Yeo-Johnson
yeo = PowerTransformer(method="yeo-johnson")
final_df[["annual_income_yj", "loan_amount_yj"]] = yeo.fit_transform(
    final_df[["annual_income", "loan_amount"]].fillna(final_df[["annual_income", "loan_amount"]].median())
)

๐Ÿ’ก Insight: Power transforms search for the optimal ฮป instead of assuming log is right. Box-Cox requires strictly positive values; Yeo-Johnson handles zeros and negatives, which is why it is the safer default here. โšก


๐Ÿงฎ Column Transformer โ†’ different preprocessing per column type
preprocessor = ColumnTransformer(transformers=[
    ("num", Pipeline([("impute", SimpleImputer(strategy="median")),
                      ("scale",  RobustScaler())]), numerical_cols),
    ("cat", Pipeline([("impute", SimpleImputer(strategy="most_frequent")),
                      ("encode", OneHotEncoder(handle_unknown="ignore"))]), categorical_cols),
])

processed = preprocessor.fit_transform(final_df)

๐Ÿ’ก Insight: The entire preprocessing strategy collapses into one reusable, leak-free object. Fit on train, apply to test โ€” no manual step can be forgotten or applied in the wrong order. ๐Ÿงท


1๏ธโƒฃ3๏ธโƒฃ Construct new features

final_df["debt_to_income"]    = final_df["loan_amount"] / final_df["annual_income"]
final_df["avg_monthly_txn"]   = final_df["transaction_count"] / 6
final_df["spend_to_income"]   = final_df["spending_ratio"] / 100
๐Ÿ’Ž Feature ๐Ÿงฎ Formula ๐Ÿ“Œ Signal
Debt-to-Income ratio loan_amount / annual_income Leverage โ€” the strongest default predictor
Average monthly transactions transaction_count / 6 Behavioural activity level
Spending-to-Income ratio spending / annual_income Financial discipline

๐Ÿ’ก Insight: These ratios encode relationships no single raw column holds. A โ‚น5L loan is unremarkable at โ‚น30L income and alarming at โ‚น4L โ€” only the ratio expresses that. ๐Ÿ’ฐ


๐Ÿ“Š Part H : Final Deliverable

partH

1๏ธโƒฃ4๏ธโƒฃ Final cleaned and transformed dataset

# 1. Missing values  โ†’ MICE (numeric) + Most Frequent (categorical)
# 2. Outliers        โ†’ Winsorize (5th / 95th percentile)
# 3. Encoding        โ†’ Ordinal + Label + One-Hot
# 4. Scaling         โ†’ Robust / Standard
# 5. Construction    โ†’ debt_to_income, avg_monthly_txn, spend_to_income

print("Missing values:", final_df.isnull().sum().sum())
print("Final shape:",    final_df.shape)

final_df.to_csv("final_processed_dataset.csv", index=False)
print("Final processed dataset saved successfully.")

๐Ÿ’ก Insight: The delivered table is fully numeric, gap-free, outlier-controlled and scaled, with the target isolated โ€” it can be handed to any estimator without a single further transformation. ๐Ÿ’พ


1๏ธโƒฃ5๏ธโƒฃ Report Summary

โ“ Question โœ… Answer
Which imputation strategy was most effective? MICE for numeric columns โ€” it estimates each gap from the relationships between all other features instead of a single statistic. Most Frequent for categoricals, since it preserves existing classes without inventing new ones.
Which outlier method preserved data quality best? Winsorization โ€” it caps extremes without deleting a single row, keeping all 1000 customers while removing the distorting influence of the tails.
Which encodings were applied and why? Ordinal only where a real order exists (education_level), Label for low-cardinality binaries (gender), One-Hot for nominal fields (region, loan_purpose).
Which scaling / transformations and why? Robust Scaling for heavy-tailed money columns; Yeo-Johnson for skewed annual_income / loan_amount because it tolerates zeros and negatives.
Are the new features useful? Yes โ€” Debt-to-Income is the single most predictive engineered signal, with spending and activity ratios adding behavioural context.
Is the dataset ML-ready? Yes โ€” zero missing values, all dtypes numeric, outliers capped, features scaled, target isolated.

workflow

๐Ÿ“‚ Project Workflow

  1. Data Acquisition โ†’ Load CSV, parse JSON, query SQL, fetch API
  2. Merge โ†’ Join all sources into one analytical base table on customer_id
  3. Understanding โ†’ .info(), .describe(), profiling report
  4. Missing Value Treatment โ†’ Mean, Mode, Random Sample, KNN, MICE, CCA
  5. Outlier Handling โ†’ Z-score, IQR, Percentile, Winsorization
  6. Feature Engineering โ†’ Date parts, Ordinal / Label / One-Hot encoding, Binning
  7. Scaling โ†’ Standard, Normalizer, Min-Max, MaxAbs, Robust
  8. Transformation โ†’ Log, Reciprocal, Sqrt, Box-Cox, Yeo-Johnson, ColumnTransformer
  9. Construction โ†’ Debt-to-Income, Avg monthly transactions, Spend-to-Income
  10. Export โ†’ Save final_processed_dataset.csv

๐Ÿ“ˆ Results & Insights

  • โœ… Four heterogeneous sources (CSV + JSON + SQL + API) merged into one clean base table of 1000 customers
  • โœ… Six imputation strategies compared โ€” MICE selected for numerics, mode for categoricals
  • โœ… Four outlier techniques compared โ€” Winsorization selected, zero rows deleted
  • โœ… Nine encoding & binning techniques applied across ordinal, nominal, binary and continuous columns
  • โœ… Five scalers and five transforms benchmarked on the same columns
  • โœ… Three engineered ratio features added, led by Debt-to-Income
  • โœ… Final dataset exported as final_processed_dataset.csv โ€” complete, stable and ML-ready

๐Ÿ“Œ Expected Outcomes

  • Understand how to plan and execute a complete data preprocessing workflow
  • Perform detailed data cleaning using imputation and outlier handling
  • Apply advanced encoding and scaling techniques with intent, not habit
  • Construct and transform features that measurably improve ML readiness

โš™๏ธ Installation & Setup

# clone the repository
git clone https://github.com/yourusername/holistic-data-preparer.git
cd holistic-data-preparer

# create an isolated environment
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

# install dependencies
pip install pandas numpy scikit-learn scipy matplotlib seaborn \
            ydata-profiling jupyter requests

# launch the notebook
jupyter notebook Holistic_Data_Preparer.ipynb

๐Ÿš€ Future Scope

  • Train baseline models (Logistic Regression, Random Forest, XGBoost) on the processed set
  • Address target imbalance with SMOTE / class weights
  • Feature importance and SHAP explainability
  • Persist the full pipeline with joblib for reproducible inference

๐Ÿ™ Thank You

Thank you for taking the time to explore this project! Your feedback, suggestions, and contributions are always welcome.

โญ If you found this project helpful, don't forget to star the repository and share it with others.


About

๐Ÿ“Š A Customer Credit Risk dataset collected from multiple sources (CSV, JSON, SQL, and an external API). perform full-scale preprocessing and feature engineering so that the dataset is clean, consistent, and suitable for building a Machine Learning model that predicts whether a customer is likely to default on a loan.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages