<jupyter_start><jupyter_text>Data available for download from Kaggle: https://www.kaggle.com/dimitaryanev/mobilechurndataxlsx<jupyter_code>import pandas as pd

# Converted to TSV for faster load times, if using the link above, use read_excel()
f_path = "data/mobile-churn-data.tsv"
df = pd.read_csv(f_path, sep='\t')
# Get rid of P.I.D. for privacy and lack of predictive value, year is all the same, so no helpful info
df = df.drop(['user_account_id', 'year'], axis=1)
df.head()
X = df.drop('churn', axis=1)
y = df[['churn']]

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import scale
from sklearn.preprocessing import StandardScaler


X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.1)
def get_shape(clean=False):
    if not clean:
        iters = [X_train, y_train, X_test, y_test]
    else:
        iters = [X_train, X_train_clean, y_train, X_test, X_test_clean, y_test]
    for x in iters:
        print(x.shape)

            
get_shape()
def remove_corr_cols(data, target=['user_lifetime']):
    """Remove columns that share the same information with the target column."""
    target = ['user_lifetime']
    sorted_corr = X_train.corr()[target].sort_values(target, ascending=False)
    removing_features = sorted_corr[sorted_corr.duplicated()].index
    return data.drop(removing_features, axis=1)


def process_df(data, scale=None):
    #Remove input features with same information
    data = remove_corr_cols(data, True)
    # Make a long col name shorter & more intuitive
    data = data.rename(columns={'user_no_outgoing_activity_in_days': 'min_outgoing_inactive_days'})
    cols = data.columns
    
    if not scale:
        scale = StandardScaler()
        scale.fit(data)

    return pd.DataFrame(scale.transform(data), columns=cols), scale
X_train_clean, scale = process_df(X_train)
X_test_clean, scale = process_df(X_test, scale)

get_shape(True)
# Uncomment the next line if you need to install SMOTE aka imbalanced-learn
# conda install -c conda-forge imbalanced-learn
from imblearn.over_sampling import SMOTE
os = SMOTE()
cols = X_train_clean.columns
os_data_X, os_data_y = os.fit_sample(X_train_clean, y_train)
os_data = pd.DataFrame(data=os_data_X, columns=cols)
os_data['churn'] = os_data_y
os_data_X.columns
os_data_X.shape
print("Length of oversampled data is                                            ",len(os_data_X))
print("Number of churn whose value is 0 in oversampled data                     ",len(os_data_y[os_data.churn==0]))
print("Number of churn whose value is 1 in oversampled data in oversampled data ",len(os_data_y[os_data.churn==1]))
len(X_test_clean)
len(y_test['churn'])
from sklearn.linear_model import LogisticRegression
from sklearn import metrics

logreg = LogisticRegression(max_iter=200)

# y requires a series, not a dataframe

logreg.fit(X_train_clean, y_train['churn'])
X_test_preds = logreg.predict(X_test_clean)


# The above is accuracy without SMOTE, now let's try it with

logreg.fit(os_data_X.drop('churn', axis=1), os_data_y['churn'])
logreg.score(X_test_clean, y_test['churn'])
import numpy as np
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

logreg = LogisticRegression()
rfe = RFE(logreg, 40)
rfe = rfe.fit(os_data_X, os_data_y['churn'])

print(rfe.support_)
print(rfe.ranking_)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10426540284360189, 'fraction_numerical': 0.004146919431279621, 'mean_word_length': 4.75298126064736, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '374040', 'license': 'MIT', 'n_tokens_mistral': 1195, 'n_tokens_neox': 1160, 'n_words': 297, 'path': 'eda.ipynb', 'repo_name': 'UpwardTrajectory/next-best-telco', 'size': '3376'}