데이터분석

[통계분석] 데이터 분석 연습하기

바틀비 2024. 1. 17. 05:28

0. Input 데이터

1. 변수 간의 상관 분석

상대적으로 유의미한 상관관계를 보이는 변수들은 다음과 같다. (상관계수 < = - 0.01, 상관계수 >= 0.01)
Exited ~ Age, Balance, NumOfProducts, IsActiveMember.
NumOfProduct ~ Age, Balance.
이중에서 Exited와 다른 네 변수의 관계를 분석한다.

더보기
df4 = train_data[['id', 'CustomerId', 'CreditScore', 'Age', 'Balance', 'EstimatedSalary', 
       'Tenure', 'NumOfProducts', 'HasCrCard', 'IsActiveMember', 'Exited']].copy()

corr_matrix=df4.corr()

mask = np.zeros_like(corr_matrix)
mask[np.triu_indices_from(mask)] = True

f,ax=plt.subplots(figsize=(15,11))
sns.heatmap(corr_matrix, mask=mask, annot=True)
plt.suptitle('Correlation Matrix')
plt.show()

2. 단순선형 회귀분석

가장 상관과계가 큰 Age를 독립변수로 선택한다.
해당 모델을 결정계수(Adj. R-squared)를 통해 0.12의 설명력을 지니고 있음을 확인할 수 있다.
개별 독립변수 Age의 p-value는 유의수준(0.05, 0.01)보다 낮으므로 귀무가설을 기각, Age가 Exited에 영향이 있다고 판단할 수 있다.
그러나 기울기 값(coef)이 0.0157로 크지 않다.

더보기
import statsmodels
import statsmodels.formula.api as smf

model = ols(formula = 'Exited ~ Age', data = train_data).fit()
model.summary()

3. 다중 회귀분석

3. 1

상관계수가 높은 변수, Age, Balance, NumOfProduct, IsActiveMember 을 독립변수로 한다.

해당 모델을 결정계수(Adj. R-squared)를 통해 0.193의 설명력을 지니고 있음을 확인할 수 있다.
각각의 독립변수의 p-value 모두 유의수준(0.05, 0.01)보다 낮으므로 귀무가설을 기각, 통계적으로 유의하다.
Balance의 기울기(coef)가 0에 가까우므로 표준화 작업을 진행한 다음 다시 회귀 분석을 한다.

더보기
import statsmodels
import statsmodels.formula.api as smf

formula = "Exited ~ Age + Balance + NumOfProducts + IsActiveMember"
model = ols(formula, data = train_data).fit()
model.summary()

3. 2 Balance 변수 표준화

더보기
target_data = train_data.copy()

from sklearn.preprocessing import StandardScaler

std=StandardScaler()
std.fit(target_data[['Balance']])
target_data[['Balance']] = std.transform(target_data[['Balance']])
target_data

3. 3 다중 회귀분석 2번째

해당 모델을 결정계수(Adj. R-squared)는 표준화 이전과 변화가 없고 모든 p-value가 여전히 유의수준보다 낮음을 확인할 수 있다.
개별 독립변수 Balance의 coef값이 0.0203으로 바뀌었음을 확인할 수 있다.

더보기
formula = "Exited  ~ Age  +Balance+ NumOfProducts + IsActiveMember"
model2 = smf.ols(formula, data = target_data).fit()
model2.summary()

 

3.4 결론

상관계수, 회귀분석의 결과, Age, Balance, NumOfProducts, IsActiveMember 네가지 독립변수 모두 종속변수 Exited와 관계가 있다.

4. 데이터 시각화를 통한 Exited와 나머지 변수의 관계 분석

4.1 데이터 설명

  • Age: 고객의 나이
  • Balance: 고객 계좌의 잔액
  • NumOfProducts: 고객이 사용하는 은행 상품의 개수 (예적금, 신용카드 등)
  • IsActiveMember: 고객이 활성멤버인지 아닌지 (1 = 활성, 0 = 비활성)
  • Exited: 고객의 은행 서비스 이탈 여부 (1 = 이탈, 0 = 이탈하지 않음, 유지)

4.2 Exited와 Age 관계 확인

이탈하지 않은 고객(Exited = 0) 중 Age(나이) 30대 중반 ~ 40대 초반의 고객이 많았다.

이탈 고객(Exited -1)의 나이는 30대 후반 ~ 50대 초반까지 상대적으로 고르게 분포 되어있다.

이탈 고객의 나이대가 이탈하지 않은 고객의 나이대보다 상대적으로 고르게 분포되어 있다. 그러나 두 그룹 모두 30대 후반 ~ 40대 초반에 많은 데이터가 있음을 확인할 수 있다.

더보기
fig, ax = plt.subplots(3, 1, figsize = (9, 20))

sns.histplot(data=train_data, x='Age', hue="Exited", bins=20, kde=True, ax = ax[0])
ax[0].set_title('Age Histogram')

sns.histplot(data=train_data.loc[train_data["Exited"] == 0], x='Age', hue="Exited", bins=20, kde=True, ax = ax[1], palette = 'Set1')
ax[1].set_title('Exited == 0 only')

sns.histplot(data=train_data.loc[train_data["Exited"] == 1], x='Age', hue="Exited", bins=20, kde=True, ax = ax[2], palette = 'Set2')
ax[2].set_title('Exited == 1 only')

plt.show()

4.3 Exited와 NumOfProduct 관계 확인

가입한 상품의 개수가 2개인 고객이 가장 많고 그 뒤를 이어 1개인 고객이 많다. 3~4개 상품을 가입한 고객도 소수 존재한다.
이탈하지 않은 고객(Exited = 0) 중 가입한 상품의 개수가 1~2개인 데이터가 많았고 특히 2개가 제일 많았다. 3 ~ 4개인 데이터는 유의미하게 적었다.
이탈 고객(Exited -1)은 상품을 1개만 가입했을 때가 다른 경우보다 유의미하게 많았다. 이탈하지 않은 고객보다 가입 상품 수 3 ~ 4개인 고객의 비중이 큰 것을 확인할 수 있다. 

더보기
f, ax = plt.subplots(1, 3, figsize=(15, 7))

sns.countplot(x='NumOfProducts', data=train_data, ax = ax[0], hue = 'NumOfProducts', legend =False)
ax[0].set_title('Total')

sns.countplot(x='NumOfProducts', data=train_data.loc[train_data["Exited"] == 0], ax = ax[1], hue = 'NumOfProducts', legend =False)
ax[1].set_title('Exited == 0')

sns.countplot(x='NumOfProducts', data=train_data.loc[train_data["Exited"] == 1], ax = ax[2], hue = 'NumOfProducts', legend =False)
ax[2].set_title('Exited == 1')

plt.show()

1개의 상품만 이용하는 고객(NumOfProduct == 1)들 중 65.3% 이탈하지 않았고 34.7%가 이탈했다.
2개의 상품에 가입한 고객은 무려 94%가 이탈하지 않았다.
3 ~ 4개의 상품을 이용하는 고객의 약 88%는 은행에서 이탈했다.

더보기
#Num이 i인 고객들의 Exited 비율 계산
#i in range(1, 4)
subset_data1 = train_data[train_data['NumOfProducts'] == 1]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})
subset_data2 = train_data[train_data['NumOfProducts'] == 2]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})
subset_data3 = train_data[train_data['NumOfProducts'] == 3]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})
subset_data4 = train_data[train_data['NumOfProducts'] == 4]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})

# 파이 차트 그리기
fig, ax = plt.subplots(2, 2, figsize=(10, 10))

# 'Exited'가 0인 값의 파이 차트
ax[0, 0].pie(subset_data1, labels=subset_data1.index, autopct='%1.1f%%', startangle=90, colors=['skyblue', 'lightcoral'])
ax[0, 0].set_title('Num = 1')

ax[0, 1].pie(subset_data2, labels=subset_data2.index, autopct='%1.1f%%', startangle=90, colors=['skyblue', 'lightcoral'])
ax[0, 1].set_title('Num = 2')

ax[1, 0].pie(subset_data3, labels=subset_data3.index, autopct='%1.1f%%', startangle=90, colors=['lightcoral', 'skyblue'])
ax[1, 0].set_title('Num = 3')

ax[1, 1].pie(subset_data4, labels=subset_data4.index, autopct='%1.1f%%', startangle=90, colors=['lightcoral', 'skyblue'])
ax[1, 1].set_title('Num = 4')

# 그래프 출력
plt.show()

위의 정보를 종합하면 대부분의 고객은 1~2개의 상품을 이용한다. 1개의 상품에만 가입되어 있을 경우 적지 않은 확률로 은행에 이탈하나 2개의 상품에 가입되어 있으면 높은 확률로 이탈하지 않는다.
상대적으로 적은 비중의 고객들은 3~4개의 상품에 가입하지만 88% 정도가 은행에서 이탈하는 모습을 보인다.

4.4 Exited와 Balance 관계 확인

Exited와 Balance의 관계를 확인하기 위해 히스토그램을 생성한다.
이때 매우 많은 수의 Balance == 0 데이터들을 확인할 수 있었고 해당 데이터들이 히스토그램의 해석을 방해하고 있었다.
그러므로 Balance를 0인 경우와 0이 아닌 경우로 나눠서 다시 차트를 생성하였다. 이때 Balance가 0인 경우는 파이 차트로 표현하여 Exited의 비중을 확인한다.
아래의 정보를 통해서 은행 계좌의 잔액이 0원임에도 이탈하지 않는 고객이 83.8%나 됨을 확인할 수 있다.

더보기
f,ax=plt.subplots(3,1,figsize=(10,20))

sns.histplot(data=train_data, x='Balance', hue="Exited", bins=50, kde=True, ax = ax[0])

subset_data1 = train_data[train_data['Balance'] == 0]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})
ax[1].pie(subset_data1, labels=subset_data1.index, autopct='%1.1f%%', startangle=90, colors=['lightcoral', 'skyblue'])
ax[1].set_title('Balance == 0')

subset_data2 = train_data[train_data['Balance'] != 0]
sns.histplot(data=subset_data2, x='Balance', hue="Exited", bins=50, kde = True, ax = ax[2])
ax[2].set_title('Balance != 0')

plt.show()

4.4 Exited와 IsActiveMember 관계 확인

전체 고객 중 은행 계좌가 활성화된 상태( IsActiveMember == 1)인 고객과 비활성화된 상태 ( IsActiveMember == 0)인 고객의 각각의 비중은 거의 절반에 가깝다.
비활성화 상태의 고객 중 이탈하지 않은 고객의 비중은 70.3%이고 활성화 상태의 고객 중 이탈하지 않은 고객은 87.5%이다.
그러므로 활성화 상태라면 고객의 대부분은 이탈하지 않고 비활성화 상태여도 70%의 고객은 이탈하지 않는다는 해석이 가능하다.

더보기
fig, ax = plt.subplots(3, 1, figsize=(8,15))

subset_data = train_data['IsActiveMember'].value_counts().rename({0: 'IsActiveMember = 0', 1: 'IsActiveMember = 1'})
ax[0].pie(subset_data, labels=subset_data.index, autopct='%1.1f%%', startangle=90, colors=['lightcoral', 'skyblue'])
ax[0].set_title('IsActiveMem')

subset_data1 = train_data[train_data['IsActiveMember'] == 0]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})
ax[1].pie(subset_data1, labels=subset_data1.index, autopct='%1.1f%%', startangle=90, colors=['lightcoral', 'skyblue'])
ax[1].set_title('IsActive == 0 & Exited')

subset_data2 = train_data[train_data['IsActiveMember'] == 1]['Exited'].value_counts().rename({0: 'Exited = 0', 1: 'Exited = 1'})
ax[2].pie(subset_data2, labels=subset_data2.index, autopct='%1.1f%%', startangle=90, colors=['lightcoral', 'skyblue'])
ax[2].set_title('IsActive == 1 & Exited')

plt.show()