<jupyter_start><jupyter_text>Logistic RegressionTo predict whether a customer will churn based on customer data To begin, as usual, import the required modules:<jupyter_code>import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pickle

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, jaccard_score, classification_report, log_loss

%matplotlib inline<jupyter_output><empty_output><jupyter_text>Get the dataset and see a sample:<jupyter_code>df = pd.read_csv("../datasets/ChurnData.csv")
df.head()<jupyter_output><empty_output><jupyter_text>and some data description:<jupyter_code>df.describe()<jupyter_output><empty_output><jupyter_text>Separate the desired features into the feature array and normalize its values:<jupyter_code>X = np.asarray(df[['tenure', 'age', 'address', 'income', 'ed', 'employ', 'equip']])
X = StandardScaler().fit_transform(X)<jupyter_output><empty_output><jupyter_text>and separate the label into another array:<jupyter_code>y = np.asarray(df['churn'].astype(int))<jupyter_output><empty_output><jupyter_text>Split the dataset into training and test data:<jupyter_code>X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)<jupyter_output><empty_output><jupyter_text>Initialize the model and fit it to the training data (the best solver in this case seems to be `liblinear` as also shown in the solution book, and this was the best value of C parameter I could find, though 0.001 would also give the same result /)-_-)<jupyter_code>model = LogisticRegression(C=.000815565, solver='liblinear')
model.fit(X_train, y_train)<jupyter_output><empty_output><jupyter_text>Use this model on test data:<jupyter_code>pred = model.predict(X_test)<jupyter_output><empty_output><jupyter_text>Also get the prediction probabilities for the test data:<jupyter_code>pred_prob = model.predict_proba(X_test)<jupyter_output><empty_output><jupyter_text>Let's see how well it has worked (a 100% accuracy would correspond to every point on the graph below the 0.5 mark being violet and every mark above the mark being red):<jupyter_code>plt.scatter(range(len(pred_prob)), [x[1] for x in pred_prob], c=y_test, cmap='rainbow')
plt.hlines(0.5, 0, 40)
plt.colorbar()
plt.xlabel("Data")
plt.ylabel("Probability")
plt.show()<jupyter_output><empty_output><jupyter_text>Let's see the Jaccard Score for the model, where 100% accuracy is represented by a score of 1:<jupyter_code>print(f"Jaccard Similarity Score of the model: {jaccard_score(y_test, pred)}")<jupyter_output>Jaccard Similarity Score of the model: 0.34782608695652173<jupyter_text>and the Confusion Matrix, which displays the number of:$[[\space true\space positive\space\space\vert\space false\space negative\space]$$[\space false\space positive\space\vert\space true\space negative\space\space]]$<jupyter_code>print(f"Confustion Matrix: \n{confusion_matrix(y_test, pred)}")<jupyter_output>Confustion Matrix: 
[[17 14]
 [ 1  8]]<jupyter_text>Also, let's get a look at the more detailed Classification Report:<jupyter_code>print(f"Classification Report: \n\n{classification_report(y_test, pred)}")<jupyter_output>Classification Report: 

              precision    recall  f1-score   support

           0       0.94      0.55      0.69        31
           1       0.36      0.89      0.52         9

    accuracy                           0.62        40
   macro avg       0.65      0.72      0.61        40
weighted avg       0.81      0.62      0.65        40<jupyter_text>Another useful metric is the Log Loss:<jupyter_code>print(f"Log Loss: {log_loss(y_test, pred_prob)}")<jupyter_output>Log Loss: 0.6800949531733015<jupyter_text>Finally, let's save the model:<jupyter_code>pickle.dump(model, open('../saved_models/model_7.sav', 'wb'))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1038265306122449, 'fraction_numerical': 0.031377551020408165, 'mean_word_length': 5.55685618729097, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '657228', 'license': 'CC0-1.0', 'n_tokens_mistral': 1413, 'n_tokens_neox': 1312, 'n_words': 330, 'path': 'my_attempts/model_7.ipynb', 'repo_name': 'goddard-guryon/fictional-fiesta', 'size': '3920'}