모든 비즈니스는 고객의 충성도에 의존합니다. 고객이 다시 거래를 해주는 것은 사업 수익성의 핵심 기반이며, 따라서 고객이 이탈하는 이유를 파악하는 것이 매우 중요합니다. 이렇게 고객이 떠나가는 현상을 고객 이탈(Customer Churn)이라고 부릅니다. 과거 데이터의 경향을 분석하면 어떤 요인이 고객 이탈에 영향을 미치는지 판단할 수 있고, 특정 고객이 이탈할지 여부도 예측할 수 있습니다.
이 글에서는 머신러닝 알고리즘을 활용해 과거 고객 이탈 데이터의 패턴을 분석하고, 앞으로 이탈 가능성이 높은 고객을 예측하는 방법을 단계별로 살펴보겠습니다.
1. 데이터 준비
이번 예제에서는 통신사(Telecom) 고객 이탈 데이터셋을 사용합니다. 원본 데이터는 Kaggle에서 무료로 내려받을 수 있으며, 아래 코드에 다운로드 URL을 함께 표시해 두었습니다. Pandas 라이브러리를 사용해 CSV 파일을 파이썬 프로그램으로 불러온 뒤 샘플 행 몇 개를 확인해 보겠습니다.
예제 코드
import pandas as pd
# Telco-Customer-Churn.csv 데이터셋 로드
# 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]2. 기존 패턴 분석
다음으로, 데이터셋에서 이탈이 발생하는 기존 패턴을 찾아봅니다. 분석에 영향을 주지 않는 컬럼은 제거하는 것이 좋습니다. 예를 들어 'customerID' 컬럼은 고객의 이탈 여부와 무관하므로 drop() 메서드와 pop() 메서드를 사용해 삭제합니다. 그런 다음, 데이터셋 내 이탈 고객의 비율을 시각화한 파이 차트를 그려보겠습니다.
예제 코드
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams
# Telco-Customer-Churn.csv 데이터셋 로드
# https://www.kaggle.com/blastchar/telco-customer-churn
datainput = pd.read_csv('E:\\Telecom_customers.csv')
print("Given input data :\n",datainput)
# 불필요한 컬럼 삭제
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()실행 결과
위 코드를 실행하면 이탈 고객과 유지 고객의 비율이 담긴 파이 차트가 화면에 나타납니다. 일반적으로 이 데이터셋에서는 이탈 고객이 전체의 약 26~27% 수준인 것을 확인할 수 있습니다.
3. 데이터 전처리
머신러닝 알고리즘이 데이터를 사용할 수 있도록 모든 필드에 숫자 라벨을 부여해야 합니다. 텍스트 값을 숫자형 플래그로 변환하는 작업입니다. 예를 들어 성별(gender) 컬럼의 값 'Male'과 'Female'을 각각 1과 0으로 바꾸는 식입니다. 이렇게 하면 해당 필드들이 이탈 여부에 미치는 영향을 계산하고 평가하는 알고리즘에서 활용할 수 있습니다. 여기서는 scikit-learn의 LabelEncoder 메서드를 사용합니다.
예제 코드
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)
# 특성(X)과 라벨(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)실행 결과
라벨 인코딩 후에는 모든 범주형 값이 0과 같은 숫자로 변환되어 있음을 확인할 수 있습니다. 또한 타깃 변수 y(Churn)와 나머지 특성 X를 분리하여 학습 준비를 마칩니다.
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 ... [7043 rows x 20 columns]
4. 데이터 학습 및 테스트
이제 데이터셋을 학습용(train)과 테스트용(test) 두 부분으로 나눕니다. test_size 파라미터는 전체 데이터 중 테스트에 사용할 비율을 결정합니다. 이 과정을 통해 우리가 만든 모델에 대한 신뢰도를 확보할 수 있습니다. 이후 로지스틱 회귀(Logistic Regression) 알고리즘을 적용해 예측값을 산출합니다.
예제 코드
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
from sklearn.linear_model import LogisticRegression
# 데이터셋 로드 및 전처리
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()
for col in ['gender','Partner','Dependents','PhoneService','MultipleLines',
'InternetService','OnlineSecurity','OnlineBackup','DeviceProtection',
'TechSupport','StreamingTV','StreamingMovies','Contract',
'PaperlessBilling','PaymentMethod','Churn']:
datainput[col] = label_encoder.fit_transform(datainput[col])
# 특성(X)과 라벨(Y) 분리
datainput["Churn"] = datainput["Churn"].astype(int)
Y = datainput["Churn"].values
X = datainput.drop(labels = ["Churn"],axis = 1)
# train_test_split으로 데이터 분할
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)
# 로지스틱 회귀 학습 및 예측
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]
5. 모델 평가 지표 확인
모델의 정확도가 충분히 나왔다면, 다양한 평가 지표를 통해 모델을 더 깊이 검증합니다. 여기서는 정확도(Accuracy)와 혼동 행렬(Confusion Matrix)을 평가 지표로 사용합니다. 정확도가 높을수록 모델의 적합성이 좋다는 의미입니다. 혼동 행렬은 참 양성(True Positive), 참 음성(True Negative), 거짓 양성(False Positive), 거짓 음성(False Negative)을 행렬 형태로 보여주며, 실제 값(True)의 비율이 오류 값(False)보다 높을수록 더 우수한 모델임을 나타냅니다.
예제 코드
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
# (앞선 전처리·학습 과정 동일)
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]]
약 80.8%의 정확도가 나왔으며, 혼동 행렬에서도 대각선 방향의 올바른 예측 건수(928건, 211건)가 오분류 건수보다 많은 것을 볼 수 있습니다.
6. 변수별 가중치 분석
마지막으로 각 변수가 이탈 값에 어떤 영향을 주는지 판단해 보겠습니다. 이를 통해 이탈에 큰 영향을 미치는 핵심 변수를 찾아내고, 고객 이탈을 막기 위해 해당 요소들을 집중 관리할 수 있습니다. 학습된 분류기의 계수(coefficient)를 추출하면 각 변수의 가중치(weight)를 구할 수 있습니다.
예제 코드
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
from sklearn.linear_model import LogisticRegression
# (앞선 전처리·학습 과정 동일)
classifier=LogisticRegression()
classifier.fit(X_train,Y_train)
Y_pred=classifier.predict(X_test)
# 모든 변수의 가중치 출력
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
결론
가중치 분석 결과를 보면 PaperlessBilling(전자 청구서), SeniorCitizen(고령 고객), InternetService(인터넷 서비스) 등은 이탈 확률을 높이는 방향(+), 반면 PhoneService, Contract(계약 기간), TechSupport(기술 지원) 등은 이탈 확률을 낮추는 방향(-)으로 작용합니다. 특히 장기 계약이나 기술 지원 서비스를 이용하는 고객의 이탈률이 현저히 낮다는 점은, 통신사가 고객 유지 전략을 세울 때 중요한 인사이트가 됩니다. 이처럼 파이썬과 scikit-learn만으로도 손쉽게 고객 이탈 예측 모델을 구축하고, 실무에 바로 적용할 수 있는 마케팅·CRM 전략 도출이 가능합니다.