<jupyter_start><jupyter_text>**Project Summary:**Telco is concerned about its significant customer attrition rate and has asked Codeup's Data Science team to identify drivers of churn. To do this, we created a machine learning model which predicts future customer churn as accurately as possible. **Project Goals:**- Find drivers for customer churn at Telco- Construct a ML classification model that accurately predicts customer churn. **Using a Random Forest Model, we identified the following predictors of churn:**- lack of tech support- month-to-month contract- non-enrollment in auto-pay- fiber optic internet - not subscribing to streaming movies and/or tvWe have created a csv file, ```churn_probability.csv``` which details the prediction and probability of churn for each Telco customer in our test data. We have also developed several recommendations to reduce future customer churn. All files referenced in this presentation are available in the github repository for this project:   https://github.com/barbmarques/classification-project-telco. ____________________________________________________________________________________________________  ```Planning```**Database Features**- We began with a dataset containing 24 attributes of 7,043 customers- A data dictionary is included in the README.md file on the github repository at: https://github.com/barbmarques/classification-project-telco/blob/main/README.md**Initial Questions:**- Does the type of internet service (DSL/fiber optic) have an effect customer churn?- What services (streaming/support) might increase customer retention?**The Pipeline:**  ```Plan -> Acquire -> Prepare -> Explore -> Model & Evaluate -> Deliver ```- Each step in the our process is recorded and staged on a Trello board at:  https://trello.com/b/vOXbVcbl ____________________________________________________________________________________________________  ```Acquiring the Data Set``` The data was acquired by running the ```get_telco_data()```, a function included in the ```acquire.py``` file found in our github repository. Step-by-step instructions for reproducting our findings are included in the README.md file.<jupyter_code># Necessary imports
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from prepare import train_validate_test_split

#remove warning boxes
import warnings 
warnings.filterwarnings("ignore")

#imports for acquire/prepare/explore
import acquire
import env
import prepare
import explore
from scipy import stats
import graphviz
from graphviz import Graph
from acquire import get_telco_data

# imports for modeling/evaluating
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
import logistic_regression_util
from prepare import train_validate_test_split
# Acquire the data from the telco_churn database on the Codeup data science database server. 
df = get_telco_data()
# Getting to know the data
df.customer_id.nunique()
df.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 7043 entries, 0 to 7042
Data columns (total 24 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   payment_type_id           7043 non-null   int64  
 1   contract_type_id          7043 non-null   int64  
 2   internet_service_type_id  7043 non-null   int64  
 3   customer_id               7043 non-null   object 
 4   gender                    7043 non-null   object 
 5   senior_citizen            7043 non-null   int64  
 6   partner                   7043 non-null   object 
 7   dependents                7043 non-null   object 
 8   tenure                    7043 non-null   int64  
 9   phone_service             7043 non-null   object 
 10  multiple_lines            7043 non-null   object 
 11  online_security           7043 non-null   object 
 12  online_backup             7043 non-null   object 
 13  device_protection         7043 non-null   object 
 14  tech_sup[...]<jupyter_text>Visualizing Individual Columns<jupyter_code>cat_vars = ['churn','contract_type','internet_service_type',
            'streaming_movies','streaming_tv','tech_support','device_protection','online_backup',
            'online_security', 'payment_type', 'gender']
quant_vars = ['monthly_charges','tenure']
explore.explore_univariate(df, cat_vars, quant_vars)
# cat_vars = ['churn', 'paperless_billing','contract_type','internet_service_type','multiple_lines',
#             'streaming_movies','streaming_tv','tech_support','device_protection','online_backup',
#             'online_security','phone_service', 'payment_type', 'gender','senior_citizen','partner',
#             'dependents', ]
# quant_vars = ['monthly_charges','tenure']
# explore.explore_univariate(df, cat_vars, quant_vars)<jupyter_output><empty_output><jupyter_text>____________________________________________________________________________________________________   Acquire Takeaways - Customer Characteristics:- 27% of all customers have churned- Gender is split 50/50, so it is not likely a driver of churn- 45% of all customers use some sort of automatic payments- 55% of all customers are on MTM contracts- 44% of all customers have dsl internet- 19% of all customers are senior citizens ____________________________________________________________________________________________________  ```Preparing the Data Set```The function clean_telco(df):**Handled missing values:**- total_charges has 11 missing values- these missing values are customers with zero tenure, so it was reasonable to replace NaNs with zero**Changed data types:**- data types of all categorical variables were encoded or converted to bools and then to ints/floats for compatibility with modeling algorithms (except customer_id which is alpha-numeric)- total_charges, a continuous variable, was converted to a float64**Deleted gender column**- since visualizations shows gender is as an even split, neither can be identified as a driver of churn.**Deleted duplicate columns:** - payment_type, contract_type, internet_service_type **Renamed columns**- renamed several columns to clarify the boolean value**Engineered features:** - streamer: combines steaming content: streaming_tv and/or streaming_movies - auto-pay: combines both forms of automatic payment: auto bank draft & automatic credit card charge- single-line, multi-line and no_phone_service were combined into phone__service - tenure years: represent tenure months in years (tenure/12)- four distinct features to reflect partner/dependent relationships The data was cleaned by running the ```clean_telco()``` function which is found in ```prepare.py``` file found in our github repository. Step-by-step instructions for this process are included in the README.md file.<jupyter_code>telco_churn = prepare.clean_telco(df)
telco_churn.head()

telco_churn.shape
telco_churn.info()
 train, validate, test = train_validate_test_split(telco_churn)<jupyter_output><empty_output><jupyter_text>____________________________________________________________________________________________________  ```Exploring the Data Set```<jupyter_code># # Visualizations of individual columns of TRAIN data
# cat_vars = ['auto_pay', 'e_Check', 'sends_check','month_to_month', 'one_year', 'two_year','dsl','fiber','no_internet','churn',
#             'paperless_billing','streamer','no_tech_support', 'no_device_protection','no_online_backup','no_online_security',
#             'phone_services', 'senior_citizen','is_single_no_dep','has_partner_no_dep','is_single_with_dep', 'family']
# quant_vars = ['monthly_charges','tenure_months','tenure_years']
# explore.explore_univariate(train, cat_vars, quant_vars)
# cat_vars = ['has_auto_pay', 'e_Check', 'sends_check','month_to_month', 'one_year', 'two_year','dsl','fiber','no_internet',
#             'paperless_billing','streamer','no_tech_support', 'no_device_protection','no_online_backup','no_online_security',
#             'phone_services','senior_citizen','is_single_no_dep','has_partner_no_dep','is_single_with_dep', 'family']
# quant_vars = ['monthly_charges','tenure_months','tenure_years']

# explore.explore_bivariate(train, 'has_churned', cat_vars, quant_vars)
cat_vars = ['has_auto_pay', 'fiber', 'no_tech_support','not_streamer']
quant_vars = ['monthly_charges','tenure_months','tenure_years']

explore.explore_bivariate(train, 'churn', cat_vars, quant_vars)<jupyter_output>has_auto_pay 
_____________________

         chi2       p-value  degrees of freedom
0  151.977733  6.407558e-35                   1

observed:
 has_churned      0     1   All
has_auto_pay                  
0             1473   763  2236
1             1424   283  1707
All           2897  1046  3943

expected:
              0           1
0  1642.833376  593.166624
1  1254.166624  452.833376<jupyter_text>Takeaways for Explore Visualizations:- Customers not on some type of auto pay churn more- Customers on fiber churn more- Customers without streaming services churn more- Customers without tech support churn more _______________________________________________________________________________________________________________________  Hypothesis Testing:     **1. Does whether a customer has tech support affect whether they will churn?**H*o*: There is no relationship between churn and tech support.   -- REJECTH*a*: There is a dependent relationship between tech support and churn.    Chi-Square Test- checking for relationship between two categorical variables.<jupyter_code>#crosstab for tech support and churn
observed = pd.crosstab(telco_churn['has_churned'],telco_churn['no_tech_support'])
observed
# Set our alpha
alpha = .01

#run chi2 test
chi2, p, degf, expected = stats.chi2_contingency(observed)

print(f'p-value is: {p}')
print()
print(f'chi2 = {chi2}')
print()
if p < alpha:
    print("Since p < .05, we reject the null hypothesis.")
else:
    print("We fail to reject the null")<jupyter_output>p-value is: 6.35740755126359e-176

chi2 = 799.6724332372228

Since p < .05, we reject the null hypothesis.<jupyter_text>_______________________________________________________________________________________________________________________  Hypothesis Test 2**Does having access to streaming content affect whether customers will churn?** H*o*: There is no relationship between streaming content and churn. -- REJECTH*a*: There is a dependent relationship between streaming content and churn.  Chi-Square Test- checking for relationship between two categorical variables.<jupyter_code>#crosstab for auto_pay and churn
observed_2 = pd.crosstab(telco_churn['has_churned'],telco_churn['not_streamer'])
observed_2
# Set our alpha
alpha = .01

#run chi2 test
chi2, p, degf, expected = stats.chi2_contingency(observed_2)

print(f'p-value is: {p}')
print()
print(f'chi2 = {chi2}')
print()
if p < alpha:
    print("Since p < .05, we reject the null hypothesis.")
else:
    print("We fail to reject the null")<jupyter_output>p-value is: 1.0541667201283859e-12

chi2 = 50.740591762430526

Since p < .05, we reject the null hypothesis.<jupyter_text>_______________________________________________________________________________________________________________________  Hypothesis Test 3**Does having auto pay affect whether customers will churn?**H*o*: There is no relationship between auto-pay and rate of churn. H*a*: They are dependent. Chi-Square Test- checking for relationship between two categorical variables.<jupyter_code>#crosstab for auto_pay and churn
observed_3 = pd.crosstab(telco_churn['has_churned'],telco_churn['has_auto_pay'])
observed_3
# Set our alpha
alpha = .01

#run chi2 test
chi2, p, degf, expected = stats.chi2_contingency(observed_3)

print(f'p-value is: {p}')
print()
print(f'chi2 = {chi2}')
print()
if p < alpha:
    print("Since p < .05, we reject the null hypothesis.")
else:
    print("We fail to reject the null")<jupyter_output>p-value is: 3.0278725722860343e-69

chi2 = 309.3485572016954

Since p < .05, we reject the null hypothesis.<jupyter_text>_______________________________________________________________________________________________________________________  ```Modeling & Evaluating```  Splitting Data for Modeling<jupyter_code># Splitting out target variable from X_train

features = ['no_tech_support', 'has_auto_pay','month_to_month','streamer','fiber']
target = ['has_churned']

# dropped 'has_churned' because it is target variable
# dropped 'customer_id' because it is alpha-numeric
X_train = train.drop(columns = ['has_churned', 'total_charges', 'customer_id'],axis=1)
X_validate = validate.drop(columns = ['has_churned', 'total_charges', 'customer_id'],axis=1)
X_test = test.drop(columns = ['has_churned'],axis=1)

# Establishing target as y_train -- 1 column only (our target variable)
y_train = train.has_churned
y_validate = validate.has_churned
y_test = test.has_churned<jupyter_output><empty_output><jupyter_text>_______________________________________________________________________________________________________________________  Establishing a Baseline Accuracy<jupyter_code>y_train.value_counts()
baseline = pd.DataFrame(y_train)
baseline['baseline'] = 0

# baseline.columns = ['actual','baseline']
# baseline.head()
# cross tab of our baseline versus actual
# pd.crosstab(baseline['baseline'], baseline['actual'])
# let's calculate the accuracy
# positive will be not churned
# (TP + TN) / (TP + TN + FP + FN)

#predicting not churned and the customer has not churned
TP = 2897

#predicting not churned and the customer has churned
FP = 1046

#predicting the customer has churned and they have churned
TN = 0

#predicting the customer has churned and they have not churned
FN = 0


base_acc = (TP + TN) / (TP + TN + FP + FN)

print("The baseline accuracy is",round(base_acc * 100, 2),"percent.")<jupyter_output>The baseline accuracy is 73.47 percent.<jupyter_text>_______________________________________________________________________________________________________________________  Logistic Regression Models  LR Model 1- features = ['no_tech_support', 'has_auto_pay','month_to_month','streamer','fiber']- target = ['has_churned']- Accuracy of Logistic Regression classifier on training set: 77%- Baseline = 73%<jupyter_code># Create the logistic regression
logit = LogisticRegression(random_state=123)

# specify the target and features we're using
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']
target = ['has_churned']

# Fit a model using only these specified features
# logit.fit(X_train[["age", "pclass", "fare"]], y_train)
logit.fit(X_train[features], y_train)

# Since we .fit on a subset, we .predict on that same subset of features
y_pred = logit.predict(X_train[features])

print("Baseline is", round(base_acc, 2))
print('Accuracy of Logistic Regression classifier on training set: {:.2f}'
     .format(logit.score(X_train[features], y_train)))
# make prediction
y_pred = logit.predict(X_train[features])
#classification report
print(classification_report(y_train, y_pred))<jupyter_output>precision    recall  f1-score   support

           0       0.83      0.87      0.85      2897
           1       0.58      0.50      0.54      1046

    accuracy                           0.77      3943
   macro avg       0.71      0.69      0.70      3943
weighted avg       0.76      0.77      0.77      3943<jupyter_text>Model 2- features = ['no_tech_support', 'has_auto_pay','month_to_month','fiber']- target = ['has_churned']- Accuracy of Logistic Regression classifier on training set: 78%- Baseline = 73%<jupyter_code># Create the logistic regression
logit2 = LogisticRegression(random_state=123)

# specify the target and features we're using
features2 = ['no_tech_support', 'has_auto_pay','month_to_month','fiber']
target = ['has_churned']

# Fit a model using only these specified features
logit2.fit(X_train[features2], y_train)

# Since we .fit on a subset, we .predict on that same subset of features
y_pred2 = logit2.predict(X_train[features2])

print("Baseline is", round(base_acc, 2))
print('Accuracy of Logistic Regression classifier on training set: {:.2f}'
     .format(logit2.score(X_train[features2], y_train)))

# create predictions
y_pred2 = logit2.predict(X_train[features2])
#classification report
print(classification_report(y_train, y_pred2))<jupyter_output>precision    recall  f1-score   support

           0       0.81      0.90      0.85      2897
           1       0.61      0.43      0.50      1046

    accuracy                           0.78      3943
   macro avg       0.71      0.67      0.68      3943
weighted avg       0.76      0.78      0.76      3943<jupyter_text>_______________________________________________________________________________________________________________________  Decision Tree  DT Model 1- features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']- target = ['has_churned']- Accuracy of Decision Tree classifier on training set: 77%- Baseline = 73%<jupyter_code># Generate a blank, decision tree model
clf1 = DecisionTreeClassifier(max_depth=3)

#Specify the features
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

# Train(fit) the model
dt1 = clf1.fit(X_train[features], y_train)
dt1
# Visualize the model so it can explain itself!
dot_data = export_graphviz(clf1, feature_names= features, rounded=True, filled=True, out_file=None)
graph = graphviz.Source(dot_data) 

graph.render('churn_decision_tree', view=True)
y_pred3 = clf1.predict(X_train[features])
y_pred3_proba = clf1.predict_proba(X_train[features])

#evaluate metrics
print('Accuracy of model with all features:', clf1.score(X_train[features], y_train))
print('\nThe confusion matrix:\n',confusion_matrix(y_train, y_pred))
print('\nClassification report:\n',classification_report(y_train, y_pred))
# Model score on accuracy:
accuracy = clf1.score(X_train[features],y_train)
accuracy<jupyter_output><empty_output><jupyter_text>_______________________________________________________________________________________________________________________  K-Nearest Neighbor  KNN Model 1- features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']- target = ['has_churned']- Accuracy of KNN on training set: 74% - Baseline = 73%<jupyter_code>#making the model
knn = KNeighborsClassifier()
#Specify the features
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

#train/fit the model

knn_fit = knn.fit(X_train[features], y_train)
# evaluating the model
y_pred = knn.predict(X_train[features])
# check model accuracy
accuracy = knn.score(X_train[features], y_train)
print(f'Model accuracy is {accuracy:.3}')
# Classification metrics report
# y_train is the actual labels for the target variable
# y_pred is the predictions that the model makes based off our X features

print(classification_report(y_train, y_pred))<jupyter_output>precision    recall  f1-score   support

           0       0.79      0.91      0.85      2897
           1       0.58      0.34      0.43      1046

    accuracy                           0.76      3943
   macro avg       0.68      0.63      0.64      3943
weighted avg       0.74      0.76      0.74      3943<jupyter_text>_______________________________________________________________________________________________________________________  KNN Model 2- k = 20- features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']- target = ['has_churned']- Accuracy of KNN on training set: 74% - Baseline = 73%<jupyter_code>#making the model
k = 20
knn_20 = KNeighborsClassifier(n_neighbors=k)

#Specify the features
features20 = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

#train/fit the model

knn_20_fit = knn_20.fit(X_train[features20], y_train)
# evaluating the model
y_pred_20 = knn_20_fit.predict(X_train[features20])
# check model accuracy
accuracy_20 = knn_20_fit.score(X_train[features20], y_train)
print(f'Model accuracy is {accuracy:.3}')
# Classification metrics report
# y_train is the actual labels for the target variable
# y_pred is the predictions that the model makes based off our X features

print(classification_report(y_train, y_pred))<jupyter_output>precision    recall  f1-score   support

           0       0.79      0.91      0.85      2897
           1       0.58      0.34      0.43      1046

    accuracy                           0.76      3943
   macro avg       0.68      0.63      0.64      3943
weighted avg       0.74      0.76      0.74      3943<jupyter_text>_______________________________________________________________________________________________________________________  Random Forest Model: RF Model 1- features = ['no_tech_support', 'has_auto_pay','month_to_month','streamer','fiber']- target = ['has_churned']- Accuracy of Random Forest Classifier on training set: 78%- Baseline = 73%<jupyter_code># Features to be used in the model
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

rf = RandomForestClassifier(bootstrap=True, 
                            class_weight=None, 
                            criterion='gini',
                            min_samples_leaf=3,
                            n_estimators=100,
                            max_depth=3, 
                            random_state=123)
# Fit the model 
rf.fit(X_train[features], y_train)
# Feature Importance
print(rf.feature_importances_)

# Make Predictions
y_pred = rf.predict(X_train[features])

# Estimate probability
y_pred_proba = rf.predict_proba(X_train[features])
print(classification_report(y_train, y_pred))
print('Accuracy of random forest classifier on training set: {:.2f}'
     .format(rf.score(X_train[features], y_train)))
print('Confusion Matrix:')
print(confusion_matrix(y_train, y_pred))<jupyter_output>Accuracy of random forest classifier on training set: 0.78
Confusion Matrix:
[[2608  289]
 [ 596  450]]<jupyter_text>_______________________________________________________________________________________________________________________  Run best performing model on out-of-sample data (Validate) LR Model 1- features = ['no_tech_support', 'has_auto_pay','month_to_month','streamer','fiber']- target = ['has_churned']- Accuracy of Logistic Regression Classifier on training set: 77%- Accuracy of Logistic Regression Classifier on validate set: 78%- Baseline = 73%<jupyter_code># specify the target and features we're using
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

# Make prediction for validate dataset
y_pred_validate = logit.predict(X_validate[features])


print("Model 1: solver = lbfgs, c = 1")

print('Accuracy: {:.2f}'.format(logit.score(X_validate[features], y_validate)))

print(confusion_matrix(y_validate, y_pred_validate))

print(classification_report(y_validate, y_pred_validate))<jupyter_output>Model 1: solver = lbfgs, c = 1
Accuracy: 0.77
[[1078  164]
 [ 219  230]]
              precision    recall  f1-score   support

           0       0.83      0.87      0.85      1242
           1       0.58      0.51      0.55       449

    accuracy                           0.77      1691
   macro avg       0.71      0.69      0.70      1691
weighted avg       0.77      0.77      0.77      1691<jupyter_text>_______________________________________________________________________________________________________________________  Random Forest Model: RF Model on Validate Set- features = ['no_tech_support', 'has_auto_pay','month_to_month','streamer','fiber']- target = ['has_churned']- Accuracy of Random Forest Classifier on training set: 78%- Accuracy of Random Forest Classifier on validate set: 77%- Baseline = 73%<jupyter_code># Features to be used in the model
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

rf2 = RandomForestClassifier(bootstrap=True, 
                            class_weight=None, 
                            criterion='gini',
                            min_samples_leaf=3,
                            n_estimators=100,
                            max_depth=3, 
                            random_state=123)
# Fit the model 
rf2.fit(X_validate[features], y_validate)
# Feature Importance
print(rf2.feature_importances_)

# Make Predictions
y_pred2 = rf2.predict(X_validate[features])

# Estimate probability
y_pred2_proba = rf2.predict_proba(X_validate[features])
print(classification_report(y_validate, y_pred2))
print('Accuracy of random forest classifier on validate set: {:.2f}'
     .format(rf2.score(X_validate[features], y_validate)))
print('Confusion Matrix:')
print(confusion_matrix(y_validate, y_pred2))<jupyter_output>Accuracy of random forest classifier on validate set: 0.77
Confusion Matrix:
[[1108  134]
 [ 254  195]]<jupyter_text>_______________________________________________________________________________________________________________________  TEST DATA SET Random Forest Model on Test Set- features = ['no_tech_support', 'has_auto_pay','month_to_month','streamer','fiber']- target = ['has_churned']- Accuracy of Random Forest Classifier on training set: 78%- Accuracy of Random Forest Classifier on validate set: 77%- **Accuracy of Random Forest Classifier on test set: 79%**- Baseline = 73%<jupyter_code># Features to be used in the model
features = ['no_tech_support', 'has_auto_pay','month_to_month','not_streamer','fiber']

rf3 = RandomForestClassifier(bootstrap=True, 
                            class_weight=None, 
                            criterion='gini',
                            min_samples_leaf=3,
                            n_estimators=100,
                            max_depth=3, 
                            random_state=123)
# Fit the model 
rf3.fit(X_test[features], y_test)
# Feature Importance
print(rf3.feature_importances_)

# Make Predictions
y_pred3 = rf3.predict(X_test[features])

# Estimate probability
y_pred3_proba = rf3.predict_proba(X_test[features])
print(classification_report(y_validate, y_pred2))
# Create new dataframe of test data customer (probability & prediction) to write to csv
test_churn = X_test.copy()
test_churn.drop(columns = ['senior_citizen', 'tenure_months', 'paperless_billing','monthly_charges','tenure_years', 
                           'phone_services', 'e_Check', 'sends_check',
                           'has_auto_pay', 'dsl', 'fiber', 'no_internet', 'no_tech_support', 'no_online_security', 
                           'no_online_backup', 'no_device_protection', 'not_streamer', 'is_single_no_dep',
                           'family','month_to_month', 'one_year','two_year', 'total_charges', 'has_partner_no_dep', 
                           'is_single_with_dep' ], inplace = True)
test_churn
test_churn['churn_prediction'] = y_pred3
#test_churn
prob = pd.DataFrame(y_pred3_proba, columns=['n','y'])
prob
test_churn.head()
# pd.concat([test_churn, prob], axis=1, ignore_index=True)
test_churn.shape, prob.shape
test_churn['no'] = prob.n.values
test_churn['yes'] = prob.y.values
test_churn
# write test_churn dataframe to .csv file
test_churn.to_csv('churn_probability.csv')
print('Accuracy of random forest classifier on test set: {:.2f}'
     .format(rf3.score(X_test[features], y_test)))
print('Confusion Matrix:')
print(confusion_matrix(y_test, y_pred3))<jupyter_output>Accuracy of random forest classifier on test set: 0.79
Confusion Matrix:
[[959  76]
 [216 158]]<jupyter_text>_______________________________________________________________________________________________________________________  ```Key Findings & Takeaways```**My analysis revealed that the following factors are predictors of customer churn:**- Customer does not receive technical support- Customer does not participate in auto-pay- Customer does not subscribe to streaming services- Customer is on a month-to-month contract- Customer has fiber optic internet**My recommendations to reduce churn include:** - Offering reduced prices on tech support for internet customers.- Offer packages for streaming movies and tv- Encourage customers to participate in some form of automatic payment (bank draft or credit card).- Incentivize 1- and 2-year contracts**With additional time to work on this project, I will:** - Analyze combinations of features that may be driving churn in fiber optic customers.- Run predictions involving packages of services or features- Run additional models, varying the hyperparameters to see if model performance can be improved.- Investigate our pricing structure across various services to identify if our pricing strategy may be suboptimal.**A .csv file containing a prediction of churn for customers is included for your review.**<jupyter_code>#pd.concat([test_churn, prob], axis=1)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0919145428316274, 'fraction_numerical': 0.03228687229511575, 'mean_word_length': 4.459403712732046, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 69, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '501281', 'license': 'MIT', 'n_tokens_mistral': 8999, 'n_tokens_neox': 8193, 'n_words': 2447, 'path': 'Final_Notebook.ipynb', 'repo_name': 'barbmarques/classification-project-telco', 'size': '29114'}