본문으로 바로가기

마케팅에서의 데이터 사이언스: 고객 이탈률 예측

Python 머신 러닝 모델로 고객 이탈률을 예측하여 마케팅 데이터를 의미 있는 인사이트로 전환하는 방법을 알아보세요.
업데이트됨 2026년 8월 31일  · 10분 읽다

AI로 탐색하기

ChatGPTClaudePerplexity

 

Introduction 

지난 10~15년 동안 디지털 기술의 발전으로 마케팅 전략은 크게 변화했습니다. 유명 브랜드부터 소규모 시장에 이르기까지 거래, 고객 구매, 선호도, 구매력, 구매 활동, 인구통계, 리뷰 등 방대한 데이터를 수집해 왔습니다. 이 모든 데이터는 고객이 구매 의도를 갖는 단계부터 실제 구매, 그리고 단골 고객이 되기까지 각 단계에서의 행동을 이해하는 데 도움을 줍니다. 바로 이 지점에서 데이터 사이언스의 잠재력이 발휘됩니다.

데이터 사이언스는 마케팅 빅데이터를 실행 가능한 인사이트로 전환합니다. 처음에는 직관적이지 않을 수 있는 미묘한 소비자 행동 패턴이나 동시 발생 관계도 드러냅니다. 그 결과 마케터는 타깃 오디언스에 대한 더 선명한 그림을 얻고, 신규 고객을 유치하고 기존 고객을 유지하며, 마케팅 전략을 최적화하고, 회사의 가시성을 높이고, 더 성공적인 광고 캠페인을 만들고, 새로운 채널을 활용하며, 궁극적으로 회사의 매출을 크게 극대화할 수 있습니다.

마케팅에서 가장 전형적인 데이터 사이언스 활용 사례 중 하나가 고객 이탈률 예측입니다. 이 주제를 조금 더 자세히 살펴보겠습니다.

마케팅에서의 데이터 사이언스 활용: 고객 이탈률 예측

고객 이탈은 사용 중이던 서비스의 구독을 취소하여 더 이상 그 서비스의 고객이 되지 않는 경향을 말합니다. 고객 이탈률은 미리 정의된 기간 동안 이탈한 고객의 비율입니다. 신규 고객을 추적하는 고객 성장률과는 반대 개념입니다.

고객 이탈률은 고객 만족도와 기업 전반의 건강도를 나타내는 매우 중요한 지표입니다. 어느 비즈니스에서나 항상 발생하는 자연 이탈이나 일부 서비스에 전형적인 계절적 이탈 외에도, 회사 내에 문제가 있어 수정해야 함을 시사하는 요인들이 있습니다. 이러한 요인은 다음과 같습니다.

  • 고객 지원의 부재 또는 낮은 품질,
  • 부정적인 고객 경험,
  • 더 나은 조건이나 가격 정책을 제공하는 경쟁사로의 전환,
  • 고객의 우선순위 변화,
  • 오랜 기간 이용한 고객의 불만족,
  • 서비스가 고객의 기대에 미치지 못함,
  • 재정적 문제,
  • 고객 결제에 대한 사기 방지 이슈.

높은 고객 이탈률은 다음과 같은 이유로 어떤 회사에도 심각한 문제를 의미합니다.

  • 회사 매출 감소와 상관관계가 있습니다.
  • 기존 고객을 유지하는 것보다 신규 고객을 확보하는 데 훨씬 더 많은 비용이 듭니다. 특히 경쟁이 치열한 시장일수록 그렇습니다.
  • 열악한 고객 서비스로 인한 이탈의 경우, 불만족한 전(前)고객이 소셜 미디어나 리뷰 사이트에 남긴 부정적 리뷰로 회사의 평판이 크게 훼손될 수 있습니다.

고객 유지율은 모든 구독형 서비스에서 비즈니스 전략의 핵심 요소입니다. 고객 이탈률을 예측하고 이에 따른 예방 조치를 취하려면 고객 행동(구매 간격, 전체 이용 기간, 해지, 후속 전화 및 메시지, 온라인 활동)에 대한 정보를 수집·분석하고, 이탈 위험 고객에게 특징적인 속성과 그 조합을 파악해야 합니다. 특히 매출 기여도가 높거나 장기 고객의 경우, 누가 곧 이탈할지 미리 알면 정확히 그들에게 집중해 설득 전략을 세울 수 있습니다. 예를 들어 특별 사은품, 할인, 동일 가격으로의 구독 업그레이드, 기타 맞춤형 경험을 제안하는 전화 등을 포함할 수 있습니다.

기술적으로 고객 이탈 예측은 전형적인 머신 러닝 분류 문제로, 이탈 위험 여부에 따라 고객에게 "yes" 또는 "no" 라벨을 부여합니다. 이제 실제 데이터를 사용해 Python으로 이 사용 사례를 살펴보겠습니다.

우리는 통신 비즈니스 모델에서의 이탈을 모델링합니다. 고객은 하나의 마스터 계약 하에 통신사와 여러 서비스를 이용할 수 있습니다. 데이터셋에는 정제된 고객 활동 특성과 고객의 이탈 여부를 나타내는 라벨이 포함되어 있습니다.

데이터를 살펴보고 이탈률 분포를 확인해 보겠습니다.

import pandas as pd

telcom = pd.read_csv('telco.csv')
print(f'Number of customers: {telcom.shape[0]:,}\n'
      f'Churn values: {set(telcom['Churn'])}\n\n'
      f'Churn distribution, %:\n{round(telcom.groupby(['Churn']).size()/telcom.shape[0]*100).convert_dtypes()}')
Number of customers: 7,032
Churn values: {0, 1}

Churn distribution, %:
Churn
0    73
1    27
dtype: float64

고객의 27%가 이탈했으며, 이는 상당히 높은 비율입니다. 다만 이전 데이터 사이언스 사용 사례와 비교하면, 이 데이터셋은 심각한 클래스 불균형 문제는 없어 보입니다.

이제 머신 러닝 기법을 적용해 이탈 예측을 수행할 수 있도록 데이터를 전처리하겠습니다. 여기에는 학습·테스트 세트로의 분할과 특성 및 타깃 변수의 추출이 포함됩니다.

from sklearn.model_selection import train_test_split

target = ['Churn']
custid = ['customerID']

cols = [col for col in telcom.columns if col not in custid + target]

X = telcom[cols]
y = telcom[target]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)

첫 번째로 사용할 모델링 알고리즘은 간단한 로지스틱 회귀 분류 모델로, 이탈 라벨을 예측하고 결과의 정확도를 평가합니다.

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

lr = LogisticRegression()
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
print(f'Test accuracy: {round(accuracy_score(y_test, predictions), 4)}')
Test accuracy: 0.8009

다음으로, 로지스틱 회귀 모델에 하나의 기능을 더해 보겠습니다. 스케일링된 데이터에 L1 정규화를 적용해 모델 구축과 동시에 특성 선택을 수행합니다. 정규화 강도의 역수인 C 파라미터 값은 모델 정확도에 영향을 줍니다. 여기서는 C 값을 0.025로 설정해 보겠습니다.

lr = LogisticRegression(penalty='l1', C=0.025, solver='liblinear')
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
print(f'Test accuracy: {round(accuracy_score(y_test, predictions), 4)}')
Test accuracy: 0.7969

이제 L1 정규화의 C 파라미터를 튜닝해, 모델 복잡도를 낮추면서도 성능 지표를 유지하는 최적 값을 찾아보겠습니다. 이를 위해 다양한 C 값을 순회하며 각 값에 대해 로지스틱 회귀 모델을 만들고 성능 지표를 계산합니다.

리스트 C에는 가능한 파라미터 값이 미리 준비되어 있습니다. l1_metrics 배열은 3개의 열로 구성되며, 첫 번째는 C 값, 다음 두 개는 각각 0이 아닌 계수 개수와 모델 정확도를 위한 자리입니다. 이 접근을 시도해 보겠습니다.

 C  Non-Zero Coeffs  Accuracy
0  1.0000             23.0  0.801479
1  0.5000             22.0  0.799204
2  0.2500             21.0  0.802048
3  0.1000             20.0  0.802617
4  0.0500             18.0  0.802048
5  0.0250             13.0  0.796928
6  0.0100              5.0  0.790102
7  0.0050              3.0  0.783276
8  0.0025              2.0  0.745734

C 값이 낮아질수록 0이 아닌 계수(즉, 모델링에 사용되는 특성)의 수가 줄어 모델 복잡도가 감소하지만, 정확도도 함께 낮아집니다. 0.05가 최적값으로 보입니다. 특성 수를 18개로 줄이면서, 비정규화 모델보다 약간 높은 정확도를 보입니다.

이제 다른 모델링 알고리즘인 결정 트리 모델을 시도해 보겠습니다.

from sklearn.tree import DecisionTreeClassifier

clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print(f'Test accuracy: {round(accuracy_score(y_test, predictions), 4)}')
Test accuracy: 0.7275

과적합을 피하면서 더 정확한 모델을 선택하기 위해 트리 깊이(max_depth 파라미터)를 튜닝해 최적값을 찾을 수 있습니다. 기술적으로는 위의 로지스틱 회귀에서 최적 C 값을 선택한 과정과 매우 유사합니다. 여기서도 여러 max_depth 값을 순회하며 각 값에 대해 결정 트리를 학습시키고 성능 지표를 계산합니다.

depth_list에는 가능한 파라미터 값이 미리 준비되어 있습니다. depth_tuning 배열은 2개의 열로 구성되며, 첫 번째 열은 깊이 후보로 채워져 있고, 다른 열은 정확도를 위한 자리입니다. 이 방법을 적용해 최적 트리 깊이를 찾아보겠습니다.

depth_list = list(range(2, 15))
depth_tuning = np.zeros((len(depth_list), 2))
depth_tuning[:, 0] = depth_list

for index in range(len(depth_list)):
    clf = DecisionTreeClassifier(max_depth=depth_list[index])
    clf.fit(X_train, y_train)
    predictions = clf.predict(X_test)
    depth_tuning[index, 1] = accuracy_score(y_test, predictions)
   
col_names = ['Max_Depth', 'Accuracy']
print(pd.DataFrame(depth_tuning, columns=col_names))
 Max_Depth  Accuracy
0         2.0  0.756542
1         3.0  0.783276
2         4.0  0.782708
3         5.0  0.791809
4         6.0  0.778157
5         7.0  0.780432
6         8.0  0.757110
7         9.0  0.762230
8        10.0  0.763936
9        11.0  0.752560
10       12.0  0.745165
11       13.0  0.732651
12       14.0  0.727531

정확도는 깊이가 증가하면서 처음에는 상승하다가 이후 하락합니다. max_depth가 5일 때 정확도가 가장 높으므로, 이를 최적 트리 깊이로 간주할 수 있습니다.

로지스틱 회귀와 결정 트리 모델 모두에서 최적 파라미터 값을 확인했으므로, 각 모델을 재구축한 뒤 이탈을 높이거나 낮추는 주요 요인을 찾아 해석해 보겠습니다.

먼저 로지스틱 회귀 모델에서는 최종 계수의 지수값을 추출해 살펴보겠습니다.

# Reconstructing the best model
lr = LogisticRegression(penalty='l1', C=0.05, solver='liblinear')
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)

# Combining feature names and coefficients into one dataframe
feature_names = pd.DataFrame(X_train.columns, columns=['Feature'])
log_coef = pd.DataFrame(np.transpose(lr.coef_), columns=['Coefficient'])
coefficients = pd.concat([feature_names, log_coef], axis=1)

# Calculating exponents of the coefficients
coefficients['Exp_Coefficient'] = np.exp(coefficients['Coefficient'])

# Removing coefficients that are equal to zero
coefficients = coefficients[coefficients['Coefficient']!=0]
print(coefficients.sort_values(by=['Exp_Coefficient']))
                          Feature  Coefficient  Exp_Coefficient
21                          tenure    -0.907750         0.403431
4                 PhoneService_Yes    -0.820517         0.440204
17               Contract_Two year    -0.595271         0.551413
8                  TechSupport_Yes    -0.418254         0.658195
16               Contract_One year    -0.414158         0.660896
5               OnlineSecurity_Yes    -0.412228         0.662173
6                 OnlineBackup_Yes    -0.143100         0.866667
3                   Dependents_Yes    -0.039299         0.961463
7             DeviceProtection_Yes    -0.017465         0.982687
11            PaperlessBilling_Yes     0.071389         1.073999
1                SeniorCitizen_Yes     0.097904         1.102857
19  PaymentMethod_Electronic check     0.188533         1.207477
22                  MonthlyCharges     0.901454         2.463182

이탈 확률에 가장 큰 영향을 미치는 특성은 tenure(이용 기간)임을 확인할 수 있습니다. 일반적으로 지수값이 1보다 작으면 이탈 확률을 낮추고, 1보다 크면 이탈 확률을 높입니다.

결정 트리 모델에서는 if-else 규칙을 추출해 시각화하겠습니다.

# Reconstructing the best model
clf = DecisionTreeClassifier(max_depth=5)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)

from sklearn import tree
import graphviz

# Exporting a graphviz object from the trained decision tree
exported = tree.export_graphviz(decision_tree=clf,
                                out_file=None,
                                feature_names=cols,
                                precision=1,
                                class_names=['Not churn', 'Churn'],
                                filled=True)
graph = graphviz.Source(exported)
display(graph)

머신 러닝 결정 트리

상단부터 시작되는 일련의 if-else 규칙으로 해석할 수 있는 보기 좋은 결정 트리 시각화를 얻었습니다. 여기서도 고객의 이용 기간이 이탈을 좌우하는 가장 중요한 변수임을 확인할 수 있습니다. 트리를 더 깊게 구성하면 다른 변수들에 대한 추가 인사이트도 얻을 수 있습니다.

다음 단계로는 모델 파라미터를 추가로 조정하고, 학습/테스트 분할 방식을 달리 적용해 보며, 다른 머신 러닝 알고리즘을 적용·비교하고, 다양한 평가지표를 분석해 모델 성능을 평가할 수 있습니다.

마케팅에서의 고객 이탈률 예측과 데이터 사이언스의 다른 활용 사례를 더 깊이 탐구하고 싶다면, Machine Learning for Marketing in Python 코스가 좋은 시작점이 될 수 있습니다.

주제
데이터 사이언스
Machine Learning