Computer >> 컴퓨터 >  >> 프로그램 작성 >> Python

Python에서 고객 이탈 예측

<시간/>

모든 비즈니스는 고객의 충성도에 달려 있습니다. 고객의 반복적인 거래는 비즈니스 수익성의 초석 중 하나입니다. 따라서 고객이 회사를 떠나는 이유를 아는 것이 중요합니다. 이탈하는 고객을 고객 이탈이라고 합니다. 과거 동향을 살펴봄으로써 고객 이탈에 영향을 미치는 요인을 판단하고 특정 고객이 비즈니스를 떠날지 여부를 예측하는 방법을 판단할 수 있습니다. 이 기사에서는 ML 알고리즘을 사용하여 고객 이탈의 과거 추세를 연구한 다음 이탈 가능성이 있는 고객을 판단합니다.

데이터 준비

예를 들어 이 기사에서 Telecom 고객 이탈을 고려할 것입니다. 소스 데이터는 kaggel에서 사용할 수 있습니다. 데이터를 다운로드할 수 있는 URL은 아래 프로그램에 언급되어 있습니다. Pandas 라이브러리를 사용하여 csv 파일을 Python 프로그램에 로드하고 일부 샘플 행을 살펴봅니다.

import pandas as pd
#Loading the Telco-Customer-Churn.csv dataset
#https://www.kaggle.com/blastchar/telco-customer-churn
datainput = pd.read_csv('E:\\Telecom_customers.csv')
print("Given input data :\n",datainput)

출력

위의 코드를 실행하면 다음과 같은 결과가 나옵니다. -

Given input data :
        customerID      gender    SeniorCitizen   ...    MonthlyCharges    TotalCharges      Churn
0       7590-VHVEG      Female                0   ...             29.85           29.85         No
1       5575-GNVDE        Male                0   ...             56.95          1889.5         No
2       3668-QPYBK        Male                0   ...             53.85          108.15        Yes
3       7795-CFOCW        Male                0   ...             42.30         1840.75         No
4       9237-HQITU      Female                0   ...             70.70          151.65        Yes
...            ...         ...              ...   ...               ...             ...        ...
7038    6840-RESVB        Male                0   ...             84.80          1990.5        No
7039    2234-XADUH      Female                0   ...            103.20          7362.9        No
7040    4801-JZAZL      Female                0   ...             29.60          346.45        No
7041    8361-LTMKD        Male                1   ...             74.40           306.6       Yes
7042    3186-AJIEK        Male                0   ...            105.65          6844.5        No

[7043 rows x 21 columns]

기존 패턴 연구

다음으로 우리는 체인이 발생하는 기존 패턴을 찾기 위해 데이터 세트를 연구합니다. 또한 조건에 영향을 주지 않는 데이터 친구에서 일부 열을 삭제합니다. 예를 들어 고객 ID 열은 고객 이탈 여부에 영향을 미치지 않으므로 drop all pop 메서드를 사용하여 해당 열을 삭제합니다. 그런 다음 주어진 데이터 세트에서 확률을 보여주는 차트를 플로팅합니다.

예시 2

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams

#Loading the Telco-Customer-Churn.csv dataset
#https://www.kaggle.com/blastchar/telco-customer-churn
datainput = pd.read_csv('E:\\Telecom_customers.csv')
print("Given input data :\n",datainput)

#Dropping columns
datainput.drop(['customerID'], axis=1, inplace=True)
datainput.pop('TotalCharges')
datainput['OnlineBackup'].unique()

data = datainput['Churn'].value_counts(sort = True)
chroma = ["#BDFCC9","#FFDEAD"]
rcParams['figure.figsize'] = 9,9
explode = [0.2,0.2]
plt.pie(data, explode=explode, colors=chroma, autopct='%1.1f%%', shadow=True, startangle=180,)
plt.title('Percentage of Churn in the given Data')
plt.show()

출력

위의 코드를 실행하면 다음과 같은 결과가 나옵니다. -

Python에서 고객 이탈 예측

데이터 전처리

ML 알고리즘에서 사용할 수 있도록 데이터를 준비하기 위해 모든 필드에 레이블을 지정합니다. 또한 텍스트 값을 숫자 플래그로 변환합니다. 예를 들어, 성별 열의 값은 남성과 여성 대신 0과 1로 변경됩니다. 이는 변동 값에 대한 이러한 필드의 영향을 평가하는 계산 및 알고리즘에서 해당 필드를 사용하는 데 도움이 됩니다. sklearn의 LabelEncoder 메소드를 사용합니다.

예시 3

import pandas as pd
from sklearn import preprocessing

label_encoder = preprocessing.LabelEncoder()
datainput['gender'] = label_encoder.fit_transform(datainput['gender'])
datainput['Partner'] = label_encoder.fit_transform(datainput['Partner'])
datainput['Dependents'] = label_encoder.fit_transform(datainput['Dependents'])
datainput['PhoneService'] = label_encoder.fit_transform(datainput['PhoneService'])
datainput['MultipleLines'] = label_encoder.fit_transform(datainput['MultipleLines'])
datainput['InternetService'] = label_encoder.fit_transform(datainput['InternetService'])
datainput['OnlineSecurity'] = label_encoder.fit_transform(datainput['OnlineSecurity'])
datainput['OnlineBackup'] = label_encoder.fit_transform(datainput['OnlineBackup'])
datainput['DeviceProtection'] = label_encoder.fit_transform(datainput['DeviceProtection'])
datainput['TechSupport'] = label_encoder.fit_transform(datainput['TechSupport'])
datainput['StreamingTV'] = label_encoder.fit_transform(datainput['StreamingTV'])
datainput['StreamingMovies'] = label_encoder.fit_transform(datainput['StreamingMovies'])
datainput['Contract'] = label_encoder.fit_transform(datainput['Contract'])
datainput['PaperlessBilling'] = label_encoder.fit_transform(datainput['PaperlessBilling'])
datainput['PaymentMethod'] = label_encoder.fit_transform(datainput['PaymentMethod'])
datainput['Churn'] = label_encoder.fit_transform(datainput['Churn'])
print("input data after label encoder :\n",datainput)

#separating features(X) and label(y)
datainput["Churn"] = datainput["Churn"].astype(int)
y = datainput["Churn"].values
X = datainput.drop(labels = ["Churn"],axis = 1)
print("\nseparated X and y :")
print("y -",y)
print("X -",X)

출력

위의 코드를 실행하면 다음과 같은 결과가 나옵니다. -

input data after label encoder
      customerID       gender    SeniorCitizen ... MonthlyCharges TotalCharges    Churn
0    7590-VHVEG          0                   0 ... 29.85          29.85               0
1    5575-GNVDE          1                   0 ... 56.95          1889.5              0
2    3668-QPYBK          1                   0 ... 53.85          108.15              1
3    7795-CFOCW          1                   0 ... 42.30          1840.75             0
4    9237-HQITU          0                   0 ... 70.70          151.65              1
... ... ... ... ... ... ... ...
7038    6840-RESVB       1                   0 ...    84.80        1990.5             0
7039    2234-XADUH       0                   0 ...    103.20       7362.9             0
7040    4801-JZAZL       0                   0 ...    29.60        346.45             0
7041    8361-LTMKD       1                   1 ...    74.40         306.6             1
7042    3186-AJIEK       1                   0 ...    105.65       6844.5             0

[7043 rows x 21 columns]

separated X and y :
y - [0 0 1 ... 0 1 0]
X -       customerID       gender ...       MonthlyCharges       TotalCharges
0          7590-VHVEG          0 ...             29.85                29.85
1          5575-GNVDE          1 ...             56.95              1889.5
2          3668-QPYBK          1 ...             53.85               108.15
3          7795-CFOCW          1 ...             42.30              1840.75
4          9237-HQITU          0 ...             70.70               151.65
...          ...             ... ...             ...                   ...
7038       6840-RESVB          1 ...             84.80               1990.5
7039       2234-XADUH          0 ...             103.20              7362.9
7040       4801-JZAZL          0 ...             29.60                346.45
7041       8361-LTMKD          1 ...             74.40                306.6
7042       3186-AJIEK          1 ...             105.65               6844.5

[7043 rows x 20 columns]

데이터 교육 및 테스트

이제 데이터 세트를 두 부분으로 나눕니다. 하나는 훈련용이고 다른 하나는 테스트용입니다. test_size 매개변수는 테스트에만 사용할 데이터 세트의 백분율을 결정하는 데 사용됩니다. 이 연습은 우리가 만들고 있는 모델에 대한 자신감을 얻는 데 도움이 될 것입니다. 그런 다음 Logistic Regression 알고리즘을 적용하여 예측된 값을 찾습니다.

import pandas as pd
import warnings
warnings.filterwarnings("ignore")

from sklearn.linear_model import LogisticRegression

#Loading the Telco-Customer-Churn.csv dataset with pandas
datainput = pd.read_csv('E:\\Telecom_customers.csv')

datainput.drop(['customerID'], axis=1, inplace=True)
datainput.pop('TotalCharges')
datainput['OnlineBackup'].unique()

#LabelEncoder()
from sklearn import preprocessing
label_encoder = preprocessing.LabelEncoder()
datainput['gender'] = label_encoder.fit_transform(datainput['gender'])
datainput['Partner'] = label_encoder.fit_transform(datainput['Partner'])
datainput['Dependents'] = label_encoder.fit_transform(datainput['Dependents'])
datainput['PhoneService'] = label_encoder.fit_transform(datainput['PhoneService'])
datainput['MultipleLines'] = label_encoder.fit_transform(datainput['MultipleLines'])
datainput['InternetService'] = label_encoder.fit_transform(datainput['InternetService'])
datainput['OnlineSecurity'] = label_encoder.fit_transform(datainput['OnlineSecurity'])
datainput['OnlineBackup'] = label_encoder.fit_transform(datainput['OnlineBackup'])
datainput['DeviceProtection'] = label_encoder.fit_transform(datainput['DeviceProtection'])
datainput['TechSupport'] = label_encoder.fit_transform(datainput['TechSupport'])
datainput['StreamingTV'] = label_encoder.fit_transform(datainput['StreamingTV'])
datainput['StreamingMovies'] = label_encoder.fit_transform(datainput['StreamingMovies'])
datainput['Contract'] = label_encoder.fit_transform(datainput['Contract'])
datainput['PaperlessBilling'] = label_encoder.fit_transform(datainput['PaperlessBilling'])
datainput['PaymentMethod'] = label_encoder.fit_transform(datainput['PaymentMethod'])
datainput['Churn'] = label_encoder.fit_transform(datainput['Churn'])
#print("input data after label encoder :\n",datainput)

#separating features(X) and label(y)
datainput["Churn"] = datainput["Churn"].astype(int)
Y = datainput["Churn"].values
X = datainput.drop(labels = ["Churn"],axis = 1)

#train_test_split method
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2)

#LogisticRegression
classifier=LogisticRegression()
classifier.fit(X_train,Y_train)
Y_pred=classifier.predict(X_test)
print("\npredicted values :\n",Y_pred)

출력

위의 코드를 실행하면 다음과 같은 결과가 나옵니다. -

predicted values :
[0 0 1 ... 0 1 0]

평가 매개변수 찾기

위 단계의 정확도 수준이 허용되면 다른 매개변수를 찾아 모델에 대한 추가 평가를 진행합니다. 정확도와 혼동 행렬을 매개변수로 사용하여 이 모델이 얼마나 정확하게 작동하는지 판단합니다. 정확도 값의 백분율이 높을수록 모델이 더 적합하다는 것을 나타냅니다. 유사하게 혼동 행렬은 참 긍정, 참 부정, 거짓 긍정 및 거짓 부정의 행렬을 보여줍니다. 거짓 값에 비해 참 값의 비율이 높을수록 더 나은 모델을 나타냅니다.

import pandas as pd
import warnings
warnings.filterwarnings("ignore")
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
from sklearn.metrics import confusion_matrix

#Loading the Telco-Customer-Churn.csv dataset with pandas
datainput = pd.read_csv('E:\\Telecom_customers.csv')

datainput.drop(['customerID'], axis=1, inplace=True)
datainput.pop('TotalCharges')
datainput['OnlineBackup'].unique()

#LabelEncoder()
from sklearn import preprocessing
label_encoder = preprocessing.LabelEncoder()
datainput['gender'] = label_encoder.fit_transform(datainput['gender'])
datainput['Partner'] = label_encoder.fit_transform(datainput['Partner'])
datainput['Dependents'] = label_encoder.fit_transform(datainput['Dependents'])
datainput['PhoneService'] = label_encoder.fit_transform(datainput['PhoneService'])
datainput['MultipleLines'] = label_encoder.fit_transform(datainput['MultipleLines'])
datainput['InternetService'] = label_encoder.fit_transform(datainput['InternetService'])
datainput['OnlineSecurity'] = label_encoder.fit_transform(datainput['OnlineSecurity'])
datainput['OnlineBackup'] = label_encoder.fit_transform(datainput['OnlineBackup'])
datainput['DeviceProtection'] = label_encoder.fit_transform(datainput['DeviceProtection'])
datainput['TechSupport'] = label_encoder.fit_transform(datainput['TechSupport'])
datainput['StreamingTV'] = label_encoder.fit_transform(datainput['StreamingTV'])
datainput['StreamingMovies'] = label_encoder.fit_transform(datainput['StreamingMovies'])
datainput['Contract'] = label_encoder.fit_transform(datainput['Contract'])
datainput['PaperlessBilling'] = label_encoder.fit_transform(datainput['PaperlessBilling'])
datainput['PaymentMethod'] = label_encoder.fit_transform(datainput['PaymentMethod'])
datainput['Churn'] = label_encoder.fit_transform(datainput['Churn'])
#print("input data after label encoder :\n",datainput)

#separating features(X) and label(y)
datainput["Churn"] = datainput["Churn"].astype(int)
Y = datainput["Churn"].values
X = datainput.drop(labels = ["Churn"],axis = 1)

#train_test_split method
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2)

#LogisticRegression
classifier=LogisticRegression()
classifier.fit(X_train,Y_train)
Y_pred=classifier.predict(X_test)

#Accuracy
LR = metrics.accuracy_score(Y_test, Y_pred) * 100
print("\nThe accuracy score using the LR is -> ",LR)

#confusion matrix
cm=confusion_matrix(Y_test,Y_pred)
print("\nconfusion matrix : \n",cm)

출력

위의 코드를 실행하면 다음과 같은 결과가 나옵니다. -

The accuracy score using the LR is -> 80.8374733853797
confusion matrix :
   [[928 109]
   [161 211]]

변수의 가중치

다음으로 각 필드 또는 변수가 이탈 값에 어떤 영향을 미치는지 판단합니다. 이렇게 하면 이탈에 더 큰 영향을 미칠 특정 변수를 타겟팅하고 고객 이탈을 방지하기 위해 이러한 변수를 처리하는 데 도움이 됩니다. 이를 위해 분류기의 계수를 0으로 설정하고 각 변수의 가중치를 얻습니다.

import pandas as pd
import warnings
warnings.filterwarnings("ignore")
from sklearn.linear_model import LogisticRegression

#Loading the dataset with pandas
datainput = pd.read_csv('E:\\Telecom_customers.csv')

datainput.drop(['customerID'], axis=1, inplace=True)
datainput.pop('TotalCharges')
datainput['OnlineBackup'].unique()

#LabelEncoder()
from sklearn import preprocessing
label_encoder = preprocessing.LabelEncoder()
datainput['gender'] = label_encoder.fit_transform(datainput['gender'])
datainput['Partner'] = label_encoder.fit_transform(datainput['Partner'])
datainput['Dependents'] = label_encoder.fit_transform(datainput['Dependents'])
datainput['PhoneService'] = label_encoder.fit_transform(datainput['PhoneService'])
datainput['MultipleLines'] = label_encoder.fit_transform(datainput['MultipleLines'])
datainput['InternetService'] = label_encoder.fit_transform(datainput['InternetService'])
datainput['OnlineSecurity'] = label_encoder.fit_transform(datainput['OnlineSecurity'])
datainput['OnlineBackup'] = label_encoder.fit_transform(datainput['OnlineBackup'])
datainput['DeviceProtection'] = label_encoder.fit_transform(datainput['DeviceProtection'])
datainput['TechSupport'] = label_encoder.fit_transform(datainput['TechSupport'])
datainput['StreamingTV'] = label_encoder.fit_transform(datainput['StreamingTV'])
datainput['StreamingMovies'] = label_encoder.fit_transform(datainput['StreamingMovies'])
datainput['Contract'] = label_encoder.fit_transform(datainput['Contract'])
datainput['PaperlessBilling'] = label_encoder.fit_transform(datainput['PaperlessBilling'])
datainput['PaymentMethod'] = label_encoder.fit_transform(datainput['PaymentMethod'])
datainput['Churn'] = label_encoder.fit_transform(datainput['Churn'])
#print("input data after label encoder :\n",datainput)

#separating features(X) and label(y)
datainput["Churn"] = datainput["Churn"].astype(int)
Y = datainput["Churn"].values
X = datainput.drop(labels = ["Churn"],axis = 1)
#
#train_test_split method
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2)
#
#LogisticRegression
classifier=LogisticRegression()
classifier.fit(X_train,Y_train)
Y_pred=classifier.predict(X_test)

#weights of all the variables
wt = pd.Series(classifier.coef_[0], index=X.columns.values)
print("\nweight of all the variables :")
print(wt.sort_values(ascending=False))

출력

위의 코드를 실행하면 다음과 같은 결과가 나옵니다. -

weight of all the variables :
PaperlessBilling     0.389379
SeniorCitizen        0.246504
InternetService      0.209283
Partner              0.067855
StreamingMovies      0.054309
MultipleLines        0.042330
PaymentMethod        0.039134
MonthlyCharges       0.027180
StreamingTV         -0.008606
gender              -0.029547
tenure              -0.034668
DeviceProtection    -0.052690
OnlineBackup        -0.143625
Dependents          -0.209667
OnlineSecurity      -0.245952
TechSupport         -0.254740
Contract            -0.729557
PhoneService        -0.950555
dtype: float64