Codepython
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline as ImbPipeline
# Load dataset
churn = pd.read_csv("../datasets/TelecomCustomerChurn.csv")
# Drop ID column if present
if "customerID" in churn.columns:
churn = churn.drop("customerID", axis=1)
# Convert TotalCharges if needed
if "TotalCharges" in churn.columns:
churn["TotalCharges"] = pd.to_numeric(churn["TotalCharges"], errors="coerce")
# Target and features
X = churn.drop("Churn", axis=1)
y = churn["Churn"].map({"No": 0, "Yes": 1})
# Identify column types
categorical_cols = X.select_dtypes(include=["object"]).columns
numerical_cols = X.select_dtypes(exclude=["object"]).columns
# Numeric pipeline
num_pipeline = Pipeline([
("imputer", SimpleImputer(strategy="median"))
])
# Categorical pipeline
cat_pipeline = Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("encoder", OneHotEncoder(drop="first", handle_unknown="ignore"))
])
# Preprocessor
preprocessor = ColumnTransformer([
("num", num_pipeline, numerical_cols),
("cat", cat_pipeline, categorical_cols)
])
# Full pipeline with SMOTE
pipeline = ImbPipeline([
("preprocessing", preprocessor),
("smote", SMOTE(random_state=42)),
("model", RandomForestClassifier(random_state=42))
])
# Train-test split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# Hyperparameter space
param_dist = {
"model__n_estimators": [100, 200, 300, 500],
"model__max_depth": [None, 10, 20, 30],
"model__min_samples_split": [2, 5, 10],
"model__min_samples_leaf": [1, 2, 4],
"model__max_features": ["sqrt", "log2", None]
}
# Randomized search
random_search = RandomizedSearchCV(
pipeline,
param_distributions=param_dist,
n_iter=5,
cv=2,
scoring="accuracy",
n_jobs=1,
verbose=2,
random_state=42
)
# Train model
random_search.fit(X_train, y_train)
# Best model
best_model = random_search.best_estimator_
# Predictions
y_pred = best_model.predict(X_test)
# Evaluation
print("Best Parameters:", random_search.best_params_)
print("Accuracy:", accuracy_score(y_test, y_pred))
print("\nClassification Report:\n", classification_report(y_test, y_pred))
Output
Fitting 2 folds for each of 5 candidates, totalling 10 fits
[CV] END model__max_depth=30, model__max_features=None, model__min_samples_leaf=4, model__min_samples_split=5, model__n_estimators=100; total time= 1.1s
[CV] END model__max_depth=30, model__max_features=None, model__min_samples_leaf=4, model__min_samples_split=5, model__n_estimators=100; total time= 1.1s
[CV] END model__max_depth=None, model__max_features=None, model__min_samples_leaf=1, model__min_samples_split=2, model__n_estimators=500; total time= 5.5s
[CV] END model__max_depth=None, model__max_features=None, model__min_samples_leaf=1, model__min_samples_split=2, model__n_estimators=500; total time= 5.9s
[CV] END model__max_depth=10, model__max_features=None, model__min_samples_leaf=1, model__min_samples_split=2, model__n_estimators=100; total time= 1.0s
[CV] END model__max_depth=10, model__max_features=None, model__min_samples_leaf=1, model__min_samples_split=2, model__n_estimators=100; total time= 1.0s
[CV] END model__max_depth=None, model__max_features=sqrt, model__min_samples_leaf=4, model__min_samples_split=5, model__n_estimators=300; total time= 0.9s
[CV] END model__max_depth=None, model__max_features=sqrt, model__min_samples_leaf=4, model__min_samples_split=5, model__n_estimators=300; total time= 0.9s
[CV] END model__max_depth=30, model__max_features=log2, model__min_samples_leaf=4, model__min_samples_split=10, model__n_estimators=100; total time= 0.3s
[CV] END model__max_depth=30, model__max_features=log2, model__min_samples_leaf=4, model__min_samples_split=10, model__n_estimators=100; total time= 0.3s
Best Parameters: {'model__n_estimators': 300, 'model__min_samples_split': 5, 'model__min_samples_leaf': 4, 'model__max_features': 'sqrt', 'model__max_depth': None}
Accuracy: 0.7934705464868701
Classification Report:
precision recall f1-score support
0 0.85 0.87 0.86 1035
1 0.62 0.58 0.60 374
accuracy 0.79 1409
macro avg 0.73 0.73 0.73 1409
weighted avg 0.79 0.79 0.79 1409