728x90

2023-10-30 38th Class

Business Model

#️⃣ 마크 존슨 (2008) 연구의 비즈니스 모델 구성 요소

  • 고객 가치 제안: 고객을 위해 가치를 창출할 방법
  • 수익 공식: 고객에게 가치를 제공하면서 기업을 위한 가치를 창출하는 방법
  • 핵심 자원: 목표 고객에게 제안한 가치를 제공하는 데 필요한 인력, 기술, 제품, 설비, 브랜드 등의 자산
  • 핵심 절차: 규칙, 지표, 관행과 더불어 수익성있는 방식으로 고객 가치 제안을 달성하는 일을 반복적이며 대규모로 하는 방법

#️⃣ 알렉산더 오스터왈더 (2010)의 비즈니스 모델 캔버스 (9’ BLOCK)

500

  • 고객 세그먼트: 고객은 누구인가? -> 매스 마켓, 틈새시장, 멀티 사이드 시장 등
  • 가치제안: 핵심 가치는 무엇인가? -> 우수한 성능, 개인화, 탁월한 디자인 등
  • 채널: 어떻게 가치를 제안하고 전달할 것인가?
  • 고객 관계: 고객들과 어떤 관계를 맺을 것인가? -> 개별 지원, 셀프 서비스, 헌신적 지원-PB, 자동화 서비스 등
  • 수익원: 어떻게 수익을 창출할 것인가? -> 물품 판매, 대여료, 중개수수료, 가입비, 광고 등
  • 핵심 자원: 가지고있는 핵심 자원은 무엇인가? -> 물적, 인적, 지적, 재무적 자원
  • 핵심 활동: 어떤 핵심 활동을 수행해야 하나? -> 생산, 문제 해결, 플랫폼/네트워크
  • 핵심 파트너십: 누가 우리의 핵심 파트너인가? -> 전략적 동맹, 경쟁자들의 전략적 파트너십, 조인트 벤처, 안정적 공급을 위한 ‘구매자-공급자 관계’
  • 비즈니스 구조: 이 비즈니스를 유지하기 위한 비용 구조는 어떠한가? 고정비, 규모의 경제, 변동비, 범위의 경제

특징

  • 경쟁력과 지속성을 보유한 비즈니스 모델
    • 경쟁력: 명확한 고객 가치 제안, 수익 메커니즘
    • 지속성: 선순환 구조, 모방 불가능
  • 명확한 고객 가치 제안
    • 고객의 니즈를 충족하고 문제를 해결하는 방안을 제시하는 것
    • 상품의 서비스화(정수기, 구독), 면도기-면도날(프린터-토너), 역면도기-면도날(고급 승용차 부가 서비스), 프리미엄(스마트폰 게임)
    • 분할(넷플릭스), 양면 시장(유튜브)
  • 선순환 구조
  • 모방불가능성

Team Project 1 - 데이터 분석 프로젝트

데이터셋
Credit Card Customers
https://www.kaggle.com/datasets/sakshigoyal7/credit-card-customers

주제
신용카드 이탈 고객 예측 모델 및 타겟 마케팅 대응 전략

개요

  • 신용카드 이탈 고객 데이터 분석
  • 신용카드 이탈 고객 예측 머신러닝 모델 제작
  • 이탈 고객 예측 모델을 활용한 이탈위험고객 파악 및 대응 전략 (타겟 마케팅)

EDA

#️⃣ 변수 분석

shape = (10127, 20)

['Attrition_Flag', 'Customer_Age', 'Gender', 'Dependent_count', 'Education_Level', 'Marital_Status',
'Income_Category', 'Card_Category', 'Months_on_book', 'Total_Relationship_Count', 'Months_Inactive_12_mon',
'Contacts_Count_12_mon', 'Credit_Limit', 'Total_Revolving_Bal', 'Avg_Open_To_Buy', 'Total_Amt_Chng_Q4_Q1',
'Total_Trans_Amt', 'Total_Trans_Ct', 'Total_Ct_Chng_Q4_Q1', 'Avg_Utilization_Ratio']

종속 변인 (dependent variables, y)
Attrition_Flag (1)

범주형 변수 (categorical variables)
Gender, Education_Level, Marital_Status, Income_Category, Card_Category (5)

수치형 변수 (continuous variables)
Customer_Age, Dependent_count, Months_on_book, Total_Relationship_Count, Months_Inactive_12_mon, Contacts_Count_12_mon, Credit_Limit, Total_Revolving_Bal, Avg_Open_To_Buy, Total_Amt_Chng_Q4_Q1, Total_Trans_Amt, Total_Trans_Ct, Total_Ct_Chng_Q4_Q1, Avg_Utilization_Ratio (14)

#️⃣ 데이터 분포

[1] dependent variable (y)

  • 유지고객과 이탈고객의 비율이 imbalanced

01_attrition.png|300

  • Autogluon에서 Over Sampling 및 Under Sampling test시 원본 데이터셋이 성능지표가 더 높게 나왔음
  • Oversampling시 1627건을 8500건에 맞추는 과정에서 feature 개수 대비 records가 부족하여 overfitting이 일어나게 되었을 것 이라 예상하였음

따라서 오버나, 언더 샘플링은 하지 않고 원본을 그대로 사용하기로 결정하였음

[2] categorical variables

02_categorical.png

  • 유지, 이탈 고객은 전반적으로 유사한 데이터 분포를 보임
  • 1번 차트: 여성의 이탈이 많음
  • 3번 차트: 기혼 대비 미혼의 이탈 비율이 높음
  • 4번 차트: 자사 고객풀의 가장 큰 portion은 수입 40K 미만인 고객으로 전체의 35%에 해당
    ~40K 고객의 이탈수가 가장 많음
  • 5번 차트: Blue(최저) 등급의 고객 이탈수도 가장 많음

수입이 적고, 고객 등급이 낮을 수록 이탈하나? 라는 생각이 들었음

수입 구간별 카드 카테고리 히트맵

전체 이탈
03_card_category_income_category.png 04_card_category_income_category_attr.png
  • 하지만 데이터를 확인하면 수입이 높을 수록 등급이 높은 고객의 비율은 올라가긴 하나,
  • 모든 수입군에서 Blue, Silver 등급의 N수가 절대 다수

이탈, 유지 고객 별 고객 등급 비율

행 레이블 Blue Silver Gold Platinum 총합계
Attrited 1519(0.93) 82(0.05) 21(0.01) 5(0.003) 1627
Existing 7917(0.93) 473(0.05) 95(0.01) 15(0.001) 8500
총합계 9436 555 116 20 10127

고객 등급별 총 추정 손실액

Attrited Customer 추정 손실 합계  : Total_Trans_Amt
Blue 4,487,376
Silver 401,774
Gold 122,678
Platinum 23,779
총합계 5,035,607
  • 고객 등급별 총 추정 손실액에서도 Blue, Silver 군의 손실이 가장 크기때문에

수입이 낮고, 등급이 낮은 고객을 특정하기보다는
전반적으로 ‘등급이 낮은 고객의 이탈’이 매출 감소에 영향을 끼친 것으로 보는 것이 타당

[3] 수치형 변수

Pasted image 20231107121737.png

  • 대부분은 유사한 분포를 띔
  • 3째줄 2번째의 차트는 유지고객과 이탈고객별로 카드 거래 건수의 도수분포표
  • 이 도수 분포표를 보면 ‘유지고객에 비해 이탈고객의 카드거래 건수가 적은 것’을 확인 가능
  • 이탈고객의 최빈 구간: 1년에 30~50건 결제 구간 -> 약 3~4건/월
  • 카드거래가 활발하지 않다는 것은 Active 유저가 아니라는 의미 (주사용 카드가 아님)

이후의 분석은 액티브 유저 여부와 관련된 지표들을 중점으로 이탈 고객을 상세 분석하기로 함

#️⃣ 상세 지표 분석

이 부분은 영찬님이 맡아서 진행, 분석내용 요약은 아래와 같음

주요 분석

  • 고객 분석 - 계좌

    • 이탈 고객은 유지 고객보다 상대적으로 더 적은 개수의 계좌를 보유하는 경향을 보임
  • 고객 분석 - 문의

    • 이탈 고객은 상대적으로 유지 고객보다 더 많이 문의하는 경향을 보임
    • 유지 고객은 적게 문의하는 영역에 상대적으로 더 많이 분포
    • 문의사항이 많다는 현상은 이탈고객이 될 수 있는 전조현상으로 추정해 볼 수 있음 (불만표시)
  • 고객 분석 - 신용 한도

    • 이탈 고객 중 여성의 신용 한도가 남성에 비해 극단적으로 낮고, 밀집되어있음
    • 유지 고객의 경우 신용 한도가 낮을 수록 이용률이 높아지는 경향을 보임
  • 고객 분석 - 1분기 대비 4분기 이용 금액 (이탈 고객)

    • 왼쪽의 소액결제 고객과, 오른쪽의 고액 결제 금액 고객으로 양분화
    • 대부분의 데이터 포인트들이 y축 기준 1 이하에 분포하고있어, 연초 대비 연말에 거래 금액이 더 낮아 스팟성 고객의 가능성이 높음
  • 고객 분석 - 총 거래 건수 (이탈 고객)

    • 이탈 고객은 총 이용 건수가 낮은 곳에 대체로 분포됨
    • 이탈 고객은 1분기 대비 4분기에 이용건수가 대체로 감소함
    • 그러나 이용건수가 높은 고객이면 이용률 증가도 나타나는 경향성을 띔

Data Preprocessing

#️⃣ 수치형 변수 상관관계 분석 및 공선성 제거

수치형 변수 Corr 신용한도와 잔여한도
Pasted image 20231107123153.png Pasted image 20231107123441.png
  • Avg_Utilization_Ratio 와 상관계수가 1이고, Credit_Limit와 완전공선성을 띄는 Avg_Open_To_Buy 제거
  • Avg_Open_To_Buy 제거 후 기존에 해당 컬럼과 상관계수가 높았던 Avg_Utilization_Ratio는 피처로 사용

#️⃣ 범주형 변수 인코딩

df['Attrition_Flag'] = df['Attrition_Flag'].apply(lambda x: 0 if x == 'Existing Customer' else 1)

# Label Encoding
gender = {'M': 0, 'F': 1}
df['Gender']=df['Gender'].map(gender)

marital_status = {'Married': 1,'Single': 2, 'Divorced': 3}
df['Marital_Status'] = df['Marital_Status'].map(marital_status)

education_level = {'Uneducated': 1,'High School': 2, 'Graduate': 3, 'College': 4, 'Post-Graduate': 5, 'Doctorate': 6}
df['Education_Level'] = df['Education_Level'].map(education_level)

income_cat = {'Less than $40K': 1,'$40K - $60K': 2, '$60K - $80K': 3, '$80K - $120K': 4, '$120K +': 5}
df['Income_Category'] = df['Income_Category'].map(income_cat)

card_cat = {'Blue': 1, 'Silver': 2, 'Gold': 3, 'Platinum': 4}
df['Card_Category'] = df['Card_Category'].map(card_cat)
  • 종속변수(y), 명목변수(nominal), 서열변수(ordinal) 총 3가지 중에서
  • y -> 이분형 종속 변수로 existing: 0, attrited: 1
  • nomial -> 원핫 인코딩
  • ordinal -> 라벨 인코딩 하였음

#️⃣ 범주형 변수 결측치 대체: KNN

[1] Unknown 결측치 결정 여부

범주형 변수 중 Education_Level, Marital_Status, Income_Category에는 Unknown이라는 값이 있었음
이 Unknown은 미응답으로, 결측치로 간주할 것인지 여부에 대해 고민하였음

  • scenario 1 : 개인정보 제공에 응답하지 않는 고객이 이탈 혹은 inactive 유저와 연관이 있을 수도 있기 때문에
    미응답도 응답의 한가지 유형으로 보아야 함
    (“니가 보낸 DM을 읽고 나서 답이 없는 게 내 답이야” - IVE의 Kitsch 가사 중…)

  • scenario 2: 미응답이더라도, 사용금액, 성별, 나이 등 다른 개인 정보를 통해 어느정도 미응답 내용을 유추 가능

scenario 2를 선택하였고, 결측치로 간주하여 데이터 처리를 하기로 결정

[2] 결측치 처리 방식

결측치는 drop, replace 2가지 경우의 수가 있는데, 결정을 위해 데이터 Count를 해봄

a. 항목 별 미응답자 수

col name num of nan
Education_Level 1519
Marital_Status 749
Income_Category 1112

항목별로 미응답자 수가 다름

b. 1개라도 Unknwon인 행 모음 => 3046 명

unknown_rows = df[(df['Education_Level'] == 'Unknown') | (df['Marital_Status'] == 'Unknown') | (df['Income_Category'] == 'Unknown')]

print(unknown_rows.shape)

'''
(3046, 19)
'''

전체 10127건 중 3046건이나 결측치로 간주해 제거하는 것은 부적절하다고 판단함

c. 전부 미응답인 행 모음 => 7명

tot_unknown_rows = df[(df['Education_Level'] == 'Unknown') & (df['Marital_Status'] == 'Unknown') & (df['Income_Category'] == 'Unknown')]

print(tot_unknown_rows.shape)

'''
(7, 19)
'''

전부 미응답한 고객은 7명밖에 되지 않아 결측치 제거 혹은 대체 어떤 방법을 선택하더라도
모델에 그렇게 큰 영향을 줄 것으로 보이지 않음

d. 유지고객, 이탈고객

Pasted image 20231107144016.png|500

  • 대부분의 고객이 응답
  • 유지고객과 이탈고객의 미응답자 비율이 비슷 (종속 변인 별 미응답자 비율이 동일한 양상)
  • 따라서 제거보다는 결측치 대체가 유리할 것으로 판단

KNN Impute

# imputing instance
imputer = KNNImputer(n_neighbors=7)
cols_to_impute = ['Marital_Status', 'Education_Level', 'Income_Category']

# Split the data and fit
X = df.drop(['Attrition_Flag'], axis=1)
y = df['Attrition_Flag']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
X_train[cols_to_impute]=imputer.fit_transform(X_train[cols_to_impute])

X_test[cols_to_impute]=imputer.transform(X_test[cols_to_impute])

train_tot = pd.concat([X_train, y_train], axis=1)
test_tot = pd.concat([X_test, y_test], axis=1)
train_tot.sort_index(ascending=True, inplace=True)
test_tot.sort_index(ascending=True, inplace=True)

df2 = pd.concat([train_tot, test_tot], axis=0)
df2.sort_index(ascending=True, inplace=True)
print(f"{df.shape = }, {df2.shape = }")

# KNN 예측값 실수를 반올림하여 정수화
for col in cols_to_impute:
    df2[col] = np.round(df2[col]).astype('int')

df2[cols_to_impute].head()

rsult

Marital_Status Education_Level Income_Category
0 1 2
1 2 3
2 1 3
3 1 2
4 1 1
  • 결측치는 train 70%, stratify=True 로 KNN Fitting
  • 결측치의 예측값은 1.1240 등 소수점으로 나오는 상태에서 반올림하여 정수로 바꿈

#️⃣ 데이터 정규화: MinMax Scaling

Model Accuracy AUC Recall Prec. F1 Kappa MCC
std Light Gradient Boosting Machine 0.9923 0.9989 0.9723 0.9796 0.9759 0.9714 0.9714
minmax Light Gradient Boosting Machine 0.9924 0.9991 0.9723 0.9802 0.9762 0.9717 0.9717
robust Light Gradient Boosting Machine 0.9914 0.9985 0.9619 0.9843 0.973 0.9679 0.9679
  • AutoML 라이브러리인 Pycaret으로 테스트 진행
  • 성능이 가장 좋았던 방법은 MinMax Scaling
  • 원핫 인코딩한 변수와 종속변수를 제외한 모든 변수에 MinMax Scaling 적용

처음에는 미처 확인을 못하고 원핫 인코딩된 변수까지 스케일링을 했음
나중에 확인해보니 0, 1 값이 -0.8 … 이런 값이 나와서 뭔가 잘못됨을 눈치채고😱
원핫인코딩 된 변수는 0, 1로 남을 수 있도록, 나머지 변수에만 스케일링을 적용했음

#️⃣ 최종 데이터 Features & 종속변수 y

  • 기존 변수

    • Customer_Age, Dependent_count, Education_Level, Income_Category, Card_Category, Months_on_book, Total_Relationship_Count, Months_Inactive_12_mon, Contacts_Count_12_mon, Credit_Limit, Total_Revolving_Bal, Total_Amt_Chng_Q4_Q1, Total_Trans_Amt, Total_Trans_Ct, Total_Ct_Chng_Q4_Q1, Avg_Utilization_Ratio (16)
  • 원핫 인코딩

    • Gender_Male, Marital_Status_Married, Marital_Status_Single, Marital_Status_Divorced (4)
  • 종속 변수

    • Attrition_Flag (1)
반응형