https://www.kaggle.com/code/akhiljethwa/playground-s4e1-eda-modeling-xgboost
연습 데이터 출처
[Kaggle] 30대와 40대 이탈 고객의 특징 비교분석 (Playground S4E1) (tistory.com)
공부하는데 도움이 된 팀원의 블로그
[멀티캠퍼스 데이터분석&엔지니어 34회차 데이터 분석 연습]
# 프로젝트 개요
- 주제: 30대와 40대 이탈 고객의 특징 비교분석
- 진행 일시: 2024.01.15 ~ 2024.01.17
# 사용된 라이브러리
- Numpy
- Pandas
- Matplotlib
- Seaborn
- scipy
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import scipy as sp
# 데이터 설명
- Bank Customer Churn Prediction dataset을 기반으로 한 딥러닝을 통해 생성된 데이터
- Bank Customer Churn Prediction dataset
# 데이터 준비
train_data = pd.read_csv('/kaggle/input/playground-series-s4e1/train.csv')
test_data = pd.read_csv('/kaggle/input/playground-series-s4e1/test.csv')
sample_submission = pd.read_csv('/kaggle/input/playground-series-s4e1/sample_submission.csv')
origional_data = pd.read_csv('/kaggle/input/bank-customer-churn-prediction/Churn_Modelling.csv')
# 변수 설명
- Customer ID: 각 고객의 고유 번호
- Surname: 고객의 성
- Credit Score: 고객의 신용 점수
- Geography: 고객의 거주 국가
- Gender: 고객의 성별
- Age: 고객의 나이
- Tenure: 고객이 은행 서비스를 사용한 연수
- Balance: 고객의 계좌 잔액
- NumOfProducts: 고객이 이용하는 은행 상품 수
- HasCrCard: 고객의 신용카드 보유 여부
- IsActiveMember: 고객의 활성화 여부
- EstimatedSalary: 고객의 예상 급여
- Exited: 고객의 이탈 여부
# 프로젝트 배경
- 데이터 탐색 중 다변량 분석에서 나이와 고객 이탈의 연관성 확인: 특정 나이대에서 이탈 고객이 많은 것으로 나타났다.
# Load data
df3 = train_data[['CreditScore', 'Age', 'Balance', 'EstimatedSalary', 'Exited']].copy()
# Mapping dictionary for label changes
exit_label_mapping = {0: 'Not Exited', 1: 'Exited'}
# Change the values in the 'Exited' column using the mapping dictionary
df3['Exited'] = df3['Exited'].map(exit_label_mapping)
# Create a pairplot
sns.pairplot(df3, hue="Exited", corner=True)
# Show the plot
plt.show()
# Grouping by age ranges
# Define the bins and corresponding labels for age groups
bins = [9, 19, 29, 39, 49, 59, 69, 79, 89, 99]
age_labels = ['10s', '20s', '30s', '40s', '50s', '60s', '70s', '80s', '90s']
# Create a new column 'Ages' in the 'train_data' DataFrame based on the specified bins and labels
train_data['Ages'] = pd.cut(train_data['Age'], bins, labels=age_labels)
# Create new datasets for each age group
group_10s = train_data.loc[train_data['Ages'] == '10s', :]
group_20s = train_data.loc[train_data['Ages'] == '20s', :]
group_30s = train_data.loc[train_data['Ages'] == '30s', :]
group_40s = train_data.loc[train_data['Ages'] == '40s', :]
group_50s = train_data.loc[train_data['Ages'] == '50s', :]
group_60s = train_data.loc[train_data['Ages'] == '60s', :]
group_70s = train_data.loc[train_data['Ages'] == '70s', :]
group_80s = train_data.loc[train_data['Ages'] == '80s', :]
group_90s = train_data.loc[train_data['Ages'] == '90s', :]
# Create a 3x3 subplot grid
fig, ax = plt.subplots(3, 3, figsize=(18, 15))
# Define age groups and corresponding DataFrames
age_groups = {'10s': group_10s, '20s': group_20s, '30s': group_30s, '40s': group_40s,
'50s': group_50s, '60s': group_60s, '70s': group_70s, '80s': group_80s, '90s': group_90s}
# Iterate over rows and columns of the subplot grid
for i, (age, group) in enumerate(age_groups.items()):
row = i // 3
col = i % 3
# Plot pie chart for each age group
pie_chart = group['Exited'].value_counts().plot.pie(autopct='%1.1f%%', ax=ax[row, col], shadow=True)
ax[row, col].set_title(age)
pie_chart.set_ylabel('')
# Add legend for 'Not Exited' and 'Exited' at the top-left corner
labels = ['Not Exited', 'Exited']
ax[row, col].legend(labels, loc='upper left')
# Set the overall title for the entire figure
plt.suptitle('Exited_Ages')
plt.show()
- 나이대별로 이탈자 비율 확인: 40대에서 이탈 고객 비율이 급격하게 증가하는 것으로 나타났다.
- ==> 30대와 40대 이탈 고객에는 어떤 차이가 있을까?
# 30대와 40대 이탈 고객의 특징 비교
# Create datasets for customers who exited in their 30s and 40s
exited_30s = group_30s.loc[group_30s['Exited'] == 1, :]
exited_40s = group_40s.loc[group_40s['Exited'] == 1, :]
# Concatenate the data for exited customers in their 30s and 40s
exited_3040s = pd.concat([exited_30s, exited_40s])
- 범주형 변수: Geography, Gender, Tenure, NumOfProducts, HasCrCard, IsActiveMember
- ==> 카이스퀘어 검정으로 30대 이탈 고객과 40대 이탈 고객에서 다른 경향을 나타내는지 확인
# Chi-square test for independence for Geography between exited customers in their 30s and 40s
# Importing necessary libraries
import numpy as np
from scipy.stats import chi2_contingency
# Creating a contingency table (cross-tab) for Ages and Geography
crcard_cross = pd.crosstab(exited_3040s['Ages'], exited_3040s['Geography'])
# Performing the Chi-square test for independence
chi2_geography, p_geography, dof, ef = chi2_contingency(crcard_cross, correction=False)
# Displaying the test statistics
print(f'Chi-square = {chi2_geography:.3f}')
print(f'p = {p_geography:.3f}')
# Interpreting the result based on the p-value
alpha = 0.05
if p_geography < alpha:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# Chi-square = 21.585
# p = 0.000
# Reject the null hypothesis.
- 30대 이탈 고객과 40대 이탈 고객의 Geography에 차이가 있는지
- 귀무가설: Ages(30대와 40대)와 Geography는 독립이다.
- 대립가설: Ages(30대와 40대)와 Geography는 독립이 아니다.
- 검정 결과: Chi-square = 21.585, p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 Geography에는 차이가 있다.
# Chi-square test for independence for Gender between exited customers in their 30s and 40s
# Creating a contingency table (cross-tab) for Ages and Gender
crcard_cross = pd.crosstab(exited_3040s['Ages'], exited_3040s['Gender'])
# Performing the Chi-square test for independence
chi2_gender, p_gender, dof, ef = chi2_contingency(crcard_cross, correction=False)
# Displaying the test statistics
print(f'Chi-square = {chi2_gender:.3f}')
print(f'p = {p_gender:.3f}')
# Interpreting the result based on the p-value
alpha = 0.05
if p_gender < alpha:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# Chi-square = 14.056
# p = 0.000
# Reject the null hypothesis.
- 30대 이탈 고객과 40대 이탈 고객의 Gender에 차이가 있는지
- 귀무가설: Ages(30대와 40대)와 Gender는 독립이다.
- 대립가설: Ages(30대와 40대)와 Gender는 독립이 아니다.
- 검정 결과: Chi-square = 14.056, p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 Gender에는 차이가 있다.
# Chi-square test for independence for Tenure between exited customers in their 30s and 40s
# Creating a contingency table (cross-tab) for Ages and Tenure
crcard_cross = pd.crosstab(exited_3040s['Ages'], exited_3040s['Tenure'])
# Performing the Chi-square test for independence
chi2_tenure, p_tenure, dof, ef = chi2_contingency(crcard_cross, correction=False)
# Displaying the test statistics
print(f'Chi-square = {chi2_tenure:.3f}')
print(f'p = {p_tenure:.3f}')
# Interpreting the result based on the p-value
alpha = 0.05
if p_tenure < alpha:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# Chi-square = 18.167
# p = 0.052
# Fail to reject the null hypothesis.
- 30대 이탈 고객과 40대 이탈 고객의 Tenure에 차이가 있는지
- 귀무가설: Ages(30대와 40대)와 Tenure는 독립이다.
- 대립가설: Ages(30대와 40대)와 Tenure는 독립이 아니다.
- 검정 결과: Chi-square = 18.167, p = 0.052
- ==> p가 유의수준 0.05보다 크므로 귀무가설 채택, 30대와 40대의 Tenure에는 차이가 없다.
# Chi-square test for independence for NumOfProducts between exited customers in their 30s and 40s
# Creating a contingency table (cross-tab) for Ages and NumOfProducts
crcard_cross = pd.crosstab(exited_3040s['Ages'], exited_3040s['NumOfProducts'])
# Performing the Chi-square test for independence
chi2_products, p_products, dof, ef = chi2_contingency(crcard_cross, correction=False)
# Displaying the test statistics
print(f'Chi-square = {chi2_products:.3f}')
print(f'p = {p_products:.3f}')
# Interpreting the result based on the p-value
alpha = 0.05
if p_products < alpha:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# Chi-square = 44.150
# p = 0.000
# Reject the null hypothesis.
- 30대 이탈 고객과 40대 이탈 고객의 NumOfProducts에 차이가 있는지
- 귀무가설: Ages(30대와 40대)와 NumOfProducts는 독립이다.
- 대립가설: Ages(30대와 40대)와 NumOfProducts는 독립이 아니다.
- 검정 결과: Chi-square = 44.150, p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 NumOfProducts에는 차이가 있다.
# Chi-square test for independence for HasCrCard between exited customers in their 30s and 40s
# Creating a contingency table (cross-tab) for Ages and HasCrCard
crcard_cross = pd.crosstab(exited_3040s['Ages'], exited_3040s['HasCrCard'])
# Performing the Chi-square test for independence
chi2_crcard, p_crcard, dof, ef = chi2_contingency(crcard_cross, correction=False)
# Displaying the test statistics
print(f'Chi-square = {chi2_crcard:.3f}')
print(f'p = {p_crcard:.3f}')
# Interpreting the result based on the p-value
alpha = 0.05
if p_crcard < alpha:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# Chi-square = 21.744
# p = 0.000
# Reject the null hypothesis.
- 30대 이탈 고객과 40대 이탈 고객의 HasCrCard에 차이가 있는지
- 귀무가설: Ages(30대와 40대)와 HasCrCard는 독립이다.
- 대립가설: Ages(30대와 40대)와 HasCrCard는 독립이 아니다.
- 검정 결과: Chi-square = 21.744, p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 HasCrCard에는 차이가 있다.
# Chi-square test for independence for IsActiveMember between exited customers in their 30s and 40s
# Creating a contingency table (cross-tab) for Ages and IsActiveMember
crcard_cross = pd.crosstab(exited_3040s['Ages'], exited_3040s['IsActiveMember'])
# Performing the Chi-square test for independence
chi2_active, p_active, dof, ef = chi2_contingency(crcard_cross, correction=False)
# Displaying the test statistics
print(f'Chi-square = {chi2_active:.3f}')
print(f'p = {p_active:.3f}')
# Interpreting the result based on the p-value
alpha = 0.05
if p_active < alpha:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# Chi-square = 40.818
# p = 0.000
# Reject the null hypothesis.
- 30대 이탈 고객과 40대 이탈 고객의 IsActiveMember에 차이가 있는지
- 귀무가설: Ages(30대와 40대)와 IsActiveMember는 독립이다.
- 대립가설: Ages(30대와 40대)와 IsActiveMember는 독립이 아니다.
- 검정 결과: Chi-square = 40.818, p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 IsActiveMember에는 차이가 있다.
- 연속형 변수: CreditScore, Balance, EstimatedSalary
- ==> 독립표본 t 검정으로 30대 이탈 고객과 40대 이탈 고객에서 다른 경향을 나타내는지 확인
# Testing homogeneity of variances for CreditScore between exited customers in their 30s and 40s
# Importing the Bartlett test
from scipy.stats import bartlett
# Performing Bartlett test for homogeneity of variances
statistic, p_value = bartlett(exited_30s['CreditScore'], exited_40s['CreditScore'])
# Setting the significance level (alpha)
alpha = 0.05
# Displaying the test statistics
print(f"p = {p_value:.3f}")
# Interpreting the result based on p-value
if p_value > alpha:
print("Homogeneity of variances can be assumed.")
else:
print("Homogeneity of variances cannot be assumed.")
# p = 0.000
# Homogeneity of variances cannot be assumed.
30대 이탈 고객과 40대 이탈 고객의 CreditScore에 차이가 있는지
- 등분산성 검정
- 귀무가설: 등분산성을 가정할 수 있다.
- 대립가설: 등분산성을 가정할 수 없다.
- 검정 결과: p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 등분산성을 가정할 수 없다.
# Independent samples t-test for CreditScore between exited customers in their 30s and 40s
# Importing the necessary library
from scipy import stats
# Performing independent samples t-test
t_crscore, p_crscore = stats.ttest_ind(exited_30s['CreditScore'], exited_40s['CreditScore'], equal_var=False)
# Displaying the test statistics
print(f"t = {t_crscore:.3f}")
print(f"p = {p_crscore:.3f}")
# Interpreting the result based on the p-value
if p_crscore < 0.05:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# t = 0.228
# p = 0.820
# Fail to reject the null hypothesis.
- 독립표본 t 검정
- 귀무가설: 30대와 40대의 CreditScore의 평균은 같다.
- 대립가설: 30대와 40대의 CreditScore의 평균은 같지 않다.
- 검정 결과: t = 0.228, p = 0.820
- ==> p가 유의수준 0.05보다 크므로 귀무가설 채택, 30대와 40대의 CreditScore의 평균은 같다.
# Testing homogeneity of variances for Balance between exited customers in their 30s and 40s
# Performing Bartlett test for homogeneity of variances
statistic, p_value = bartlett(exited_30s['Balance'], exited_40s['Balance'])
# Setting the significance level (alpha)
alpha = 0.05
# Displaying the test statistics
print(f"p = {p_value:.3f}")
# Interpreting the result based on p-value
if p_value > alpha:
print("Homogeneity of variances can be assumed.")
else:
print("Homogeneity of variances cannot be assumed.")
# p = 0.822
# Homogeneity of variances can be assumed.
30대 이탈 고객과 40대 이탈 고객의 Balance에 차이가 있는지
- 등분산성 검정
- 귀무가설: 등분산성을 가정할 수 있다.
- 대립가설: 등분산성을 가정할 수 없다.
- 검정 결과: p = 0.822
- ==> p가 유의수준 0.05보다 크므로 귀무가설 기각, 등분산성을 가정할 수 있다.
# Independent samples t-test for Balance between exited customers in their 30s and 40s
# Performing independent samples t-test
t_balance, p_balance = stats.ttest_ind(exited_30s['Balance'], exited_40s['Balance'], equal_var=True)
# Displaying the test statistics
print(f"t = {t_balance:.3f}")
print(f"p = {p_balance:.3f}")
# Interpreting the result based on the p-value
if p_balance < 0.05:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# t = 2.291
# p = 0.022
# Reject the null hypothesis.
- 독립표본 t 검정
- 귀무가설: 30대와 40대의 Balance의 평균은 같다.
- 대립가설: 30대와 40대의 Balance의 평균은 같지 않다.
- 검정 결과: t = 2.291, p = 0.022
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 Balance의 평균은 같지 않다.
# Testing homogeneity of variances for EstimatedSalary between exited customers in their 30s and 40s
# Performing Bartlett test for homogeneity of variances
statistic, p_value = bartlett(exited_30s['EstimatedSalary'], exited_40s['EstimatedSalary'])
# Setting the significance level (alpha)
alpha = 0.05
# Displaying the test statistics
print(f"p = {p_value:.3f}")
# Interpreting the result based on p-value
if p_value > alpha:
print("Homogeneity of variances can be assumed.")
else:
print("Homogeneity of variances cannot be assumed.")
# p = 0.001
# Homogeneity of variances cannot be assumed.
30대 이탈 고객과 40대 이탈 고객의 EstimatedSalary에 차이가 있는지
- 등분산성 검정
- 귀무가설: 등분산성을 가정할 수 있다.
- 대립가설: 등분산성을 가정할 수 없다.
- 검정 결과: p = 0.001
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 등분산성을 가정할 수 없다.
# Independent samples t-test for EstimatedSalary between exited customers in their 30s and 40s
# Performing independent samples t-test
t_salary, p_salary = stats.ttest_ind(exited_30s['EstimatedSalary'], exited_40s['EstimatedSalary'], equal_var=False)
# Displaying the test statistics
print(f"t = {t_salary:.3f}")
print(f"p = {p_salary:.3f}")
# Interpreting the result based on the p-value
if p_salary < 0.05:
print("Reject the null hypothesis.")
else:
print("Fail to reject the null hypothesis.")
# t = -3.966
# p = 0.000
# Reject the null hypothesis.
- 독립표본 t 검정
- 귀무가설: 30대와 40대의 EstimatedSalary의 평균은 같다.
- 대립가설: 30대와 40대의 EstimatedSalary의 평균은 같지 않다.
- 검정 결과: t = -3.966, p = 0.000
- ==> p가 유의수준 0.05보다 작으므로 귀무가설 기각, 30대와 40대의 EstimatedSalary의 평균은 같지 않다.
# 유의미한 차이를 보인 변수 시각화
- 30대와 40대에서 통계적으로 유의미한 차이를 보인 변수: Geography, Gender, NumOfProducts, HasCrCard, IsActiveMember, Balance, EstimatedSalary
# Compare Geography for customers who exited in their 30s and 40s
# Importing the necessary library
import matplotlib.pyplot as plt
# Create a 1x2 subplot grid
fig, ax = plt.subplots(1, 2, figsize=(18, 5.5))
# Iterate over age groups
for i, (age_group, exited_data) in enumerate([('30s', exited_30s), ('40s', exited_40s)]):
# Plot pie chart for Geography in each age group
exited_data['Geography'].value_counts().plot.pie(autopct='%1.1f%%', ax=ax[i], shadow=True)
ax[i].set_title(f'{age_group}')
ax[i].set_ylabel('')
# Add legend at the top-left corner
labels = ['France', 'Germany', 'Spain']
ax[i].legend(labels, loc='upper left')
# Add text below the center of the figure
fig.text(0.5, 0.05, f'Chi-square = {chi2_geography:.3f}, p = {p_geography:.3f}', ha='center', va='center')
# Set the overall title for the entire figure
plt.suptitle('Geography Comparison for Exiting Customers')
plt.show()
- Geography
- 30대에서 프랑스와 스페인 거주자가 차지하는 비율이 40대보다 높은 것으로 나타났다.
- 40대에서 독일 거주자가 차지하는 비율이 30대보다 높은 것으로 나타났다.
# Compare Gender for customers who exited in their 30s and 40s
# Importing the necessary library
import matplotlib.pyplot as plt
# Create a 1x2 subplot grid
fig, ax = plt.subplots(1, 2, figsize=(18, 5.5))
# Iterate over age groups
for i, (age_group, exited_data) in enumerate([('30s', exited_30s), ('40s', exited_40s)]):
# Plot pie chart for Gender in each age group
exited_data['Gender'].value_counts().plot.pie(autopct='%1.1f%%', ax=ax[i], shadow=True)
ax[i].set_title(f'{age_group}')
ax[i].set_ylabel('')
# Add legend at the top-left corner
labels = ['Female', 'Male']
ax[i].legend(labels, loc='upper left')
# Add text below the center of the figure
fig.text(0.5, 0.05, f'Chi-square = {chi2_gender:.3f}, p = {p_gender:.3f}', ha='center', va='center')
# Set the overall title for the entire figure
plt.suptitle('Gender Comparison for Exiting Customers')
plt.show()
- Gender
- 30대에서 남성이 차지하는 비율이 40대보다 높은 것으로 나타났다.
- 40대에서 여성이 차지하는 비율이 30대보다 높은 것으로 나타났다.
# Compare NumOfProducts for customers who exited in their 30s and 40s
# Create a 1x2 subplot grid
fig, ax = plt.subplots(1, 2, figsize=(18, 5.5))
# Iterate over age groups
for i, (age_group, exited_data) in enumerate([('30s', exited_30s), ('40s', exited_40s)]):
# Plot pie chart for Gender in each age group
exited_data['NumOfProducts'].value_counts().plot.pie(autopct='%1.1f%%', ax=ax[i], shadow=True)
ax[i].set_title(f'{age_group}')
ax[i].set_ylabel('')
# Add legend at the top-left corner
labels = ['1', '2', '3', '4']
ax[i].legend(labels, loc='upper left')
# Add text below the center of the figure
fig.text(0.5, 0.05, f'Chi-square = {chi2_products:.3f}, p = {p_products:.3f}', ha='center', va='center')
# Set the overall title for the entire figure
plt.suptitle('NumOfProducts Comparison for Exiting Customers')
plt.show()
- NumOfProducts
- 30대에서 은행 상품을 3개 사용하는 고객이 차지하는 비율이 40대보다 높은 것으로 나타났다.
- 40대에서 은행 상품을 1개, 2개, 4개 사용하는 고객이 차지하는 비율이 30대보다 높은 것으로 나타났다.
# Compare HasCrCard for customers who exited in their 30s and 40s
# Create a 1x2 subplot grid
fig, ax = plt.subplots(1, 2, figsize=(18, 5.5))
# Iterate over age groups
for i, (age_group, exited_data) in enumerate([('30s', exited_30s), ('40s', exited_40s)]):
# Plot pie chart for Gender in each age group
exited_data['HasCrCard'].value_counts().plot.pie(autopct='%1.1f%%', ax=ax[i], shadow=True)
ax[i].set_title(f'{age_group}')
ax[i].set_ylabel('')
# Add legend at the top-left corner
labels = ['Has Credit Card', 'No Credit Card']
ax[i].legend(labels, loc='upper left')
# Add text below the center of the figure
fig.text(0.5, 0.05, f'Chi-square = {chi2_crcard:.3f}, p = {p_crcard:.3f}', ha='center', va='center')
# Set the overall title for the entire figure
plt.suptitle('HasCrCard Comparison for Exiting Customers')
plt.show()
- HasCrCard
- 30대에서 신용카드를 보유하지 않은 고객이 차지하는 비율이 40대보다 높은 것으로 나타났다.
- 40대에서 신용카드를 보유한 고객이 차지하는 비율이 30대보다 높은 것으로 나타났다.
# Compare IsActiveMember for customers who exited in their 30s and 40s
# Create a 1x2 subplot grid
fig, ax = plt.subplots(1, 2, figsize=(18, 5.5))
# Iterate over age groups
for i, (age_group, exited_data) in enumerate([('30s', exited_30s), ('40s', exited_40s)]):
# Plot pie chart for Gender in each age group
exited_data['IsActiveMember'].value_counts().plot.pie(autopct='%1.1f%%', ax=ax[i], shadow=True)
ax[i].set_title(f'{age_group}')
ax[i].set_ylabel('')
# Add legend at the top-left corner
labels = ['Not Active Member', 'Active Member']
ax[i].legend(labels, loc='upper left')
# Add text below the center of the figure
fig.text(0.5, 0.05, f'Chi-square = {chi2_active:.3f}, p = {p_active:.3f}', ha='center', va='center')
# Set the overall title for the entire figure
plt.suptitle('IsActiveMember Comparison for Exiting Customers')
plt.show()
- IsActiveMember
- 30대에서 활성화되지 않은 고객이 차지하는 비율이 40대보다 높은 것으로 나타났다.
- 40대에서 활성화된 고객이 차지하는 비율이 30대보다 높은 것으로 나타났다.
# Compare Balance for customers who exited in their 30s and 40s
# Importing the necessary library
import matplotlib.pyplot as plt
# Calculate mean values for Balance
balance_mean_30s = round(exited_30s['Balance'].mean(), 2)
balance_mean_40s = round(exited_40s['Balance'].mean(), 2)
# Create a figure and axis
fig, ax = plt.subplots(figsize=(10, 6))
# Plot histograms for Balance in their 30s and 40s
ax.hist(exited_30s['Balance'], bins=30, alpha=0.5, label='30s')
ax.hist(exited_40s['Balance'], bins=30, alpha=0.5, label='40s')
# Add dashed lines for mean values
ax.axvline(balance_mean_30s, linestyle='dashed', linewidth=2, label=f'Mean (30s): {balance_mean_30s}')
ax.axvline(balance_mean_40s, color='red', linestyle='dashed', linewidth=2, label=f'Mean (40s): {balance_mean_40s}')
# Set title and labels
ax.set_title('Balance Comparison for Exiting Customers')
ax.set_xlabel('Balance')
ax.set_ylabel('')
ax.legend()
# Add text below the center of the figure
ax.text(0.5, -0.15, f't = {t_balance:.3f}, p = {p_balance:.3f}', ha='center', va='center', transform=ax.transAxes)
# Show the plot
plt.show()
- Balance
- 30대의 계좌 잔액 평균이 40대보다 높은 것으로 나타났다.
# Compare EstimatedSalary for customers who exited in their 30s and 40s
# Importing the necessary library
import matplotlib.pyplot as plt
# Calculate mean values for EstimatedSalary
salary_mean_30s = round(exited_30s['EstimatedSalary'].mean(), 2)
salary_mean_40s = round(exited_40s['EstimatedSalary'].mean(), 2)
# Create a figure and axis
fig, ax = plt.subplots(figsize=(10, 6))
# Plot histograms for EstimatedSalary in their 30s and 40s
ax.hist(exited_30s['EstimatedSalary'], bins=30, alpha=0.5, label='30s')
ax.hist(exited_40s['EstimatedSalary'], bins=30, alpha=0.5, label='40s')
# Add dashed lines for mean values
ax.axvline(salary_mean_30s, linestyle='dashed', linewidth=2, label=f'Mean (30s): {salary_mean_30s}')
ax.axvline(salary_mean_40s, color='red', linestyle='dashed', linewidth=2, label=f'Mean (40s): {salary_mean_40s}')
# Set title and labels
ax.set_title('EstimatedSalary Comparison for Exiting Customers')
ax.set_xlabel('EstimatedSalary')
ax.set_ylabel('')
ax.legend()
# Add text below the center of the figure
ax.text(0.5, -0.15, f't = {t_salary:.3f}, p = {p_salary:.3f}', ha='center', va='center', transform=ax.transAxes)
# Show the plot
plt.show()
- EstimatedSalary
- 40대의 예상 급여 평균이 30대보다 높은 것으로 나타났다.
# 결론
- 30대에서 40대로 넘어갈 때 급격한 이탈률 증가를 보였다.
- 30대와 40대 이탈 고객의 특성 중 Geography, Gender, NumOfProducts, HasCrCard, IsActiveMember, Balance, EstimatedSalary에서 차이가 나타났다.
- 이탈률이 높아지는 40대를 타겟으로 마케팅 전략을 세울 때, 다음과 같은 고려사항이 있다.
- 독일 거주자
- 여성
- 1개, 2개, 4개의 은행 상품 이용 고객
- 신용카드 보유 고객
- 활성화된 고객
- 적은 계좌 잔액
- 높은 예상 급여
# 은행 고객의 이탈에 대한 참고자료
https://www.ciokorea.com/news/37389
https://www.hankyung.com/article/2019112919496
https://www.ebn.co.kr/news/view/1436631