computerscience-person/CCS229_Customer_Churn
0
1import marimo2 3__generated_with = "0.11.20"4app = marimo.App(width="medium")5 6 7@app.cell8def _(mo):9 mo.md(r"""# Customer Churn Analysis""")10 return11 12 13@app.cell14def _():15 import marimo as mo16 import polars as pl17 import altair as alt18 return alt, mo, pl19 20 21@app.cell22def _(pl):23 df = pl.read_csv(24 "hf://datasets/louiecerv/customer_churn/customer_churn_data.csv"25 )26 df.describe()27 return (df,)28 29 30@app.cell31def _(df):32 df.head()33 return34 35 36@app.cell37def _(df, pl):38 from sklearn.preprocessing import (39 RobustScaler,40 OneHotEncoder,41 MinMaxScaler,42 OrdinalEncoder,43 )44 from sklearn.pipeline import make_pipeline45 from sklearn.compose import make_column_transformer46 from sklearn.linear_model import (47 LogisticRegression,48 BayesianRidge,49 RidgeClassifier,50 SGDClassifier,51 )52 from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis53 from sklearn.naive_bayes import BernoulliNB54 from sklearn.svm import SVC55 from sklearn.tree import DecisionTreeClassifier56 from sklearn.neighbors import KNeighborsClassifier57 from sklearn.ensemble import (58 VotingClassifier,59 BaggingClassifier,60 GradientBoostingClassifier,61 RandomForestClassifier,62 )63 from sklearn.feature_selection import RFE, RFECV, SequentialFeatureSelector64 from sklearn.model_selection import train_test_split65 66 num_features = ["tenure", "monthly_charges", "total_charges"]67 cat_features = ["contract_One Two year", "internet_service_Fiber No"]68 random_state = 3369 70 df2 = df.with_columns(71 (pl.col("contract_One year") + "_" + pl.col("contract_Two year")).alias(72 "contract_One Two year"73 ),74 (75 pl.col("internet_service_Fiber optic")76 + "_"77 + pl.col("internet_service_No")78 ).alias("internet_service_Fiber No"),79 )80 81 X, y = df2.select(num_features + cat_features), df2.select(["churn"])82 83 X_train, X_test, y_train, y_test = train_test_split(84 X, y, test_size=0.32, random_state=random_state85 )86 87 preprocessor = make_column_transformer(88 (OneHotEncoder(), cat_features),89 (MinMaxScaler(), num_features),90 )91 92 knc = KNeighborsClassifier(algorithm="ball_tree")93 dtree = DecisionTreeClassifier(criterion="entropy", random_state=random_state)94 rfc = RandomForestClassifier(95 criterion="entropy", max_features=0.3, random_state=random_state96 )97 gbc = GradientBoostingClassifier(random_state=random_state)98 bag = BaggingClassifier(99 KNeighborsClassifier(),100 max_samples=0.8,101 max_features=0.8,102 random_state=random_state,103 )104 105 log_pipe = make_pipeline(106 preprocessor, LogisticRegression(max_iter=10000, random_state=random_state)107 )108 bridge_pipe = make_pipeline(preprocessor, BayesianRidge(max_iter=10000))109 ridge_pipe = make_pipeline(110 preprocessor, RidgeClassifier(max_iter=10000, random_state=random_state)111 )112 sgd_pipe = make_pipeline(113 preprocessor,114 SGDClassifier(115 loss="hinge", penalty="l2", max_iter=10000, random_state=random_state116 ),117 )118 lda_pipe = make_pipeline(preprocessor, QuadraticDiscriminantAnalysis())119 bnb_pipe = make_pipeline(preprocessor, BernoulliNB())120 svc_pipe = make_pipeline(121 preprocessor, SVC(kernel="rbf", max_iter=10000, random_state=random_state)122 )123 dtree_pipe = make_pipeline(preprocessor, dtree)124 rfc_pipe = make_pipeline(preprocessor, rfc)125 knc_pipe = make_pipeline(preprocessor, knc)126 gbc_pipe = make_pipeline(preprocessor, gbc)127 vot_pipe = make_pipeline(128 preprocessor,129 VotingClassifier(130 estimators=[131 ("qda", QuadraticDiscriminantAnalysis()),132 ("dtree", dtree),133 ],134 voting="soft",135 weights=[5, 2],136 ),137 )138 bag_pipe = make_pipeline(preprocessor, bag)139 140 log_pred = log_pipe.fit(X_train, y_train).predict(X_test)141 bridge_pred = bridge_pipe.fit(X_train, y_train).predict(X_test)142 ridge_pred = ridge_pipe.fit(X_train, y_train).predict(X_test)143 sgd_pred = sgd_pipe.fit(X_train, y_train).predict(X_test)144 lda_pred = lda_pipe.fit(X_train, y_train).predict(X_test)145 bnb_pred = bnb_pipe.fit(X_train, y_train).predict(X_test)146 svc_pred = svc_pipe.fit(X_train, y_train).predict(X_test)147 dtree_pred = dtree_pipe.fit(X_train, y_train).predict(X_test)148 rfc_pred = dtree_pipe.fit(X_train, y_train).predict(X_test)149 knc_pred = knc_pipe.fit(X_train, y_train).predict(X_test)150 gbc_pred = gbc_pipe.fit(X_train, y_train).predict(X_test)151 vot_pred = vot_pipe.fit(X_train, y_train).predict(X_test)152 bag_pred = bag_pipe.fit(X_train, y_train).predict(X_test)153 return (154 BaggingClassifier,155 BayesianRidge,156 BernoulliNB,157 DecisionTreeClassifier,158 GradientBoostingClassifier,159 KNeighborsClassifier,160 LogisticRegression,161 MinMaxScaler,162 OneHotEncoder,163 OrdinalEncoder,164 QuadraticDiscriminantAnalysis,165 RFE,166 RFECV,167 RandomForestClassifier,168 RidgeClassifier,169 RobustScaler,170 SGDClassifier,171 SVC,172 SequentialFeatureSelector,173 VotingClassifier,174 X,175 X_test,176 X_train,177 bag,178 bag_pipe,179 bag_pred,180 bnb_pipe,181 bnb_pred,182 bridge_pipe,183 bridge_pred,184 cat_features,185 df2,186 dtree,187 dtree_pipe,188 dtree_pred,189 gbc,190 gbc_pipe,191 gbc_pred,192 knc,193 knc_pipe,194 knc_pred,195 lda_pipe,196 lda_pred,197 log_pipe,198 log_pred,199 make_column_transformer,200 make_pipeline,201 num_features,202 preprocessor,203 random_state,204 rfc,205 rfc_pipe,206 rfc_pred,207 ridge_pipe,208 ridge_pred,209 sgd_pipe,210 sgd_pred,211 svc_pipe,212 svc_pred,213 train_test_split,214 vot_pipe,215 vot_pred,216 y,217 y_test,218 y_train,219 )220 221 222@app.cell223def _(224 bag_pred,225 bnb_pred,226 bridge_pred,227 dtree_pred,228 gbc_pred,229 knc_pred,230 lda_pred,231 log_pred,232 mo,233 rfc_pred,234 ridge_pred,235 sgd_pred,236 svc_pred,237 vot_pred,238 y_test,239):240 from sklearn.metrics import (241 accuracy_score,242 precision_score,243 f1_score,244 recall_score,245 roc_auc_score,246 log_loss,247 mean_squared_error,248 root_mean_squared_error,249 mean_absolute_error,250 r2_score,251 explained_variance_score,252 )253 254 mo.md(f"""255 # Model Metrics256 257 ## Logistic Regression258 259 - Accuracy: {accuracy_score(y_test, log_pred)}260 - Precision: {precision_score(y_test, log_pred)}261 - Recall: {recall_score(y_test, log_pred)}262 - F1: {f1_score(y_test, log_pred)}263 - ROC-AUC: {roc_auc_score(y_test, log_pred)}264 - Log Loss: {log_loss(y_test, log_pred)}265 266 ## Ridge Classifier267 268 - Accuracy: {accuracy_score(y_test, ridge_pred)}269 - Precision: {precision_score(y_test, ridge_pred)}270 - Recall: {recall_score(y_test, ridge_pred)}271 - F1: {f1_score(y_test, ridge_pred)}272 - ROC-AUC: {roc_auc_score(y_test, ridge_pred)}273 - Log Loss: {log_loss(y_test, ridge_pred)}274 275 ## SGD Classifier276 277 - Accuracy: {accuracy_score(y_test, sgd_pred)}278 - Precision: {precision_score(y_test, sgd_pred)}279 - Recall: {recall_score(y_test, sgd_pred)}280 - F1: {f1_score(y_test, sgd_pred)}281 - ROC-AUC: {roc_auc_score(y_test, sgd_pred)}282 - Log Loss: {log_loss(y_test, sgd_pred)}283 284 ## Bayesian Ridge Regression285 286 - Mean Squared Error: {mean_squared_error(y_test, bridge_pred)}287 - Root Mean Squared Error: {root_mean_squared_error(y_test, bridge_pred)}288 - Mean Absolute Error: {mean_absolute_error(y_test, bridge_pred)}289 - R^2: {r2_score(y_test, bridge_pred)}290 - Explained Variance: {explained_variance_score(y_test, bridge_pred)}291 292 ## Quadratic Discriminant Analysis293 294 - Accuracy: {accuracy_score(y_test, lda_pred)}295 - Precision: {precision_score(y_test, lda_pred)}296 - Recall: {recall_score(y_test, lda_pred)}297 - F1: {f1_score(y_test, lda_pred)}298 - ROC-AUC: {roc_auc_score(y_test, lda_pred)}299 - Log Loss: {log_loss(y_test, lda_pred)}300 301 ## Bernoulli Naive Bayes302 303 - Accuracy: {accuracy_score(y_test, bnb_pred)}304 - Precision: {precision_score(y_test, bnb_pred)}305 - Recall: {recall_score(y_test, bnb_pred)}306 - F1: {f1_score(y_test, bnb_pred)}307 - ROC-AUC: {roc_auc_score(y_test, bnb_pred)}308 - Log Loss: {log_loss(y_test, bnb_pred)}309 310 ## C-Support Vector Classifier311 312 - Accuracy: {accuracy_score(y_test, svc_pred)}313 - Precision: {precision_score(y_test, svc_pred)}314 - Recall: {recall_score(y_test, svc_pred)}315 - F1: {f1_score(y_test, svc_pred)}316 - ROC-AUC: {roc_auc_score(y_test, svc_pred)}317 - Log Loss: {log_loss(y_test, svc_pred)}318 319 ## Decision Tree Classifier320 321 - Accuracy: {accuracy_score(y_test, dtree_pred)}322 - Precision: {precision_score(y_test, dtree_pred)}323 - Recall: {recall_score(y_test, dtree_pred)}324 - F1: {f1_score(y_test, dtree_pred)}325 - ROC-AUC: {roc_auc_score(y_test, dtree_pred)}326 - Log Loss: {log_loss(y_test, dtree_pred)}327 328 ## Random Forest Classifier329 330 - Accuracy: {accuracy_score(y_test, rfc_pred)}331 - Precision: {precision_score(y_test, rfc_pred)}332 - Recall: {recall_score(y_test, rfc_pred)}333 - F1: {f1_score(y_test, rfc_pred)}334 - ROC-AUC: {roc_auc_score(y_test, rfc_pred)}335 - Log Loss: {log_loss(y_test, rfc_pred)}336 337 ## K Neighbors Classifier338 339 - Accuracy: {accuracy_score(y_test, knc_pred)}340 - Precision: {precision_score(y_test, knc_pred)}341 - Recall: {recall_score(y_test, knc_pred)}342 - F1: {f1_score(y_test, knc_pred)}343 - ROC-AUC: {roc_auc_score(y_test, knc_pred)}344 - Log Loss: {log_loss(y_test, knc_pred)}345 346 ## Gradient Boosting Classifier347 348 - Accuracy: {accuracy_score(y_test, gbc_pred)}349 - Precision: {precision_score(y_test, gbc_pred)}350 - Recall: {recall_score(y_test, gbc_pred)}351 - F1: {f1_score(y_test, gbc_pred)}352 - ROC-AUC: {roc_auc_score(y_test, gbc_pred)}353 - Log Loss: {log_loss(y_test, gbc_pred)}354 355 ## Voting Classifier356 357 - Accuracy: {accuracy_score(y_test, vot_pred)}358 - Precision: {precision_score(y_test, vot_pred)}359 - Recall: {recall_score(y_test, vot_pred)}360 - F1: {f1_score(y_test, vot_pred)}361 - ROC-AUC: {roc_auc_score(y_test, vot_pred)}362 - Log Loss: {log_loss(y_test, vot_pred)}363 364 ## Bagging Classifier365 366 - Accuracy: {accuracy_score(y_test, bag_pred)}367 - Precision: {precision_score(y_test, bag_pred)}368 - Recall: {recall_score(y_test, bag_pred)}369 - F1: {f1_score(y_test, bag_pred)}370 - ROC-AUC: {roc_auc_score(y_test, bag_pred)}371 - Log Loss: {log_loss(y_test, bag_pred)}372 373 {374 mo.callout(375 "From the metrics, the Quadratic Discriminant Analysis and the Decision Tree Classifier perform the best, thus, they were chosen for the Voting Classifier",376 kind="info",377 )378 }379 """)380 return (381 accuracy_score,382 explained_variance_score,383 f1_score,384 log_loss,385 mean_absolute_error,386 mean_squared_error,387 precision_score,388 r2_score,389 recall_score,390 roc_auc_score,391 root_mean_squared_error,392 )393 394 395@app.cell396def _(mo):397 user_inputs = mo.ui.dictionary(398 {399 "tenure": mo.ui.number(label="Tenure", start=1, stop=72, step=1),400 "monthly_charges": mo.ui.number(401 label="Monthly Charges", start=20, stop=120, step=1402 ),403 "total_charges": mo.ui.number(404 label="Total Charges", start=20, stop=8000, step=1405 ),406 "contract": mo.ui.dropdown(407 label="Contract (Year)", options=["None", "One", "Two"]408 ),409 "service": mo.ui.dropdown(410 label="Service", options=["None", "Basic", "Fiber Optic"]411 ),412 }413 )414 415 mo.vstack(user_inputs.values())416 return (user_inputs,)417 418 419@app.cell420def _(mo, pl, user_inputs, vot_pipe):421 contract = None422 service = None423 424 match user_inputs["contract"].value:425 case "None":426 contract = "false_false"427 case "One":428 contract = "true_false"429 case "Two":430 contract = "false_true"431 case _:432 pass433 434 match user_inputs["service"].value:435 case "None":436 service = "false_false"437 case "Basic":438 service = "true_false"439 case "Fiber Optic":440 service = "false_true"441 case _:442 pass443 444 preds = pl.DataFrame({445 "tenure": user_inputs["tenure"].value,446 "monthly_charges": user_inputs["monthly_charges"].value,447 "total_charges": user_inputs["total_charges"].value,448 "contract_One Two year": contract,449 "internet_service_Fiber No": service,450 })451 452 prediction = (vot_pipe.predict(preds), vot_pipe.predict_proba(preds)) 453 454 mo.md(f"Prediction: {"Yes" if prediction[0][0] else "No" }, with about {prediction[1][0][0] * 100 if not prediction[0][0] else prediction[1][0][1] * 100:.2f}% probability.")455 return contract, prediction, preds, service456 457 458if __name__ == "__main__":459 app.run()460 