일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 공개API
- 이진검색
- HDD와 SSD의 차이
- 트위터해킹
- 아키네이처
- 비전공자개발정리
- 컴퓨터과학
- 1일 1로그 100일 완성 IT지식
- 네트워크해킹
- CS스터디
- es6
- es6문법
- 프로세서 속도와 심장 박동수
- 브라우저 작동원리
- ES5
- ES차이
- 한국디도스
- 주식스팸
- 빗썸데이터
- 아마존해킹
- 컴퓨터 논리와 구조
- 자바스크립트표준
- 데이터분석
- API요청
- es3
- 줌서비스
- 숫자구하기
- 알고리즘 문제 풀이
- 퀵정렬
- ECMA설명
- Today
- Total
개발일지
데이터분석 5주차 숙제 - 📄 통신사 고객 데이터를 이용한 종합적 데이터 분석 본문
여러분들이 1주차부터 5주차까지 배운 모든 내용을 이용해 아래의 데이터를
여러분의 역량이 되는 한 최대한 분석해봅시다.
👻
Q1. 탐색적 데이터 분석을 통해 각종 차트로 시각화해봅시다.
Q2. 특정 기준을 선정하여 K-means로 군집을 시도해봅시다.
Q3. 2주차에서 배운 분류 모델 중 하나를 선정하여 고객 이탈을 예측해봅시다.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv('Sparta_CodingClub_Telco_Customer.csv')
df
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7043 entries, 0 to 7042
Data columns (total 21 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 customerID 7043 non-null object
1 gender 7043 non-null object
2 SeniorCitizen 7043 non-null int64
3 Partner 7043 non-null object
4 Dependents 7043 non-null object
5 tenure 7043 non-null int64
6 PhoneService 7043 non-null object
7 MultipleLines 7043 non-null object
8 InternetService 7043 non-null object
9 OnlineSecurity 7043 non-null object
10 OnlineBackup 7043 non-null object
11 DeviceProtection 7043 non-null object
12 TechSupport 7043 non-null object
13 StreamingTV 7043 non-null object
14 StreamingMovies 7043 non-null object
15 Contract 7043 non-null object
16 PaperlessBilling 7043 non-null object
17 PaymentMethod 7043 non-null object
18 MonthlyCharges 7043 non-null float64
19 TotalCharges 7043 non-null object
20 Churn 7043 non-null object
dtypes: float64(1), int64(2), object(18)
memory usage: 1.1+ MB
Churn : 고객 이탈 여부, 종속 변수. customerID : 고객의 고유한 ID. gender : 고객 성별. SeniorCitizen : 고객이 노약자인가 아닌가. Partner : 고객에게 파트너가 있는지 여부(결혼 여부). Dependents : 고객의 부양 가족 여부. tenure : 고객이 회사에 머물렀던 개월 수. PhoneService : 고객에게 전화 서비스가 있는지 여부. MultipleLines : 고객이 여러 회선을 사용하는지 여부. InternetService : 고객의 인터넷 서비스 제공업체. OnlineSecurity : 고객의 온라인 보안 여부. OnlineBackup : 고객이 온라인 백업을 했는지 여부. DeviceProtection : 고객에게 기기 보호 기능이 있는지 여부. TechSupport : 고객이 기술 지원을 받았는지 여부. StreamingTV : 고객이 스트리밍TV을 가지고 있는지 여부. StreamingMovies : 고객이 영화를 스트리밍하는지 여부. Contract : 고객의 계약기간. PaperlessBilling : 고객의 종이 없는 청구서 수신 여부(모바일 청구서). PaymentMethod : 고객의 결제 수단. MonthlyCharges : 매월 고객에게 청구되는 금액. TotalCharges : 고객에게 청구된 총 금액.
df['customerID'].nunique()
7043
df.describe()
여기서 잘 관찰을 하시다가 이상한 점을 찾아내셔야 하는데, TotalCharges라는 열이 현재 object(문자열) 데이터로 취급이 되고 있습니다. 문자열 데이터를 수치형 데이터로 변환을 시도합니다.
df['TotalCharges'] = pd.to_numeric(df['TotalCharges'])
그러면 에러가 발생하는데 " "라는 값이 존재하고 있어서 변환이 불가능하다는 의미입니다. " " 값을 0 으로 바꿔주는 작업을 진행하겠습니다.
df['TotalCharges'] = df['TotalCharges'].replace({" ": 0})
df['TotalCharges'] = pd.to_numeric(df['TotalCharges'])
df
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7043 entries, 0 to 7042
Data columns (total 21 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 customerID 7043 non-null object
1 gender 7043 non-null object
2 SeniorCitizen 7043 non-null int64
3 Partner 7043 non-null object
4 Dependents 7043 non-null object
5 tenure 7043 non-null int64
6 PhoneService 7043 non-null object
7 MultipleLines 7043 non-null object
8 InternetService 7043 non-null object
9 OnlineSecurity 7043 non-null object
10 OnlineBackup 7043 non-null object
11 DeviceProtection 7043 non-null object
12 TechSupport 7043 non-null object
13 StreamingTV 7043 non-null object
14 StreamingMovies 7043 non-null object
15 Contract 7043 non-null object
16 PaperlessBilling 7043 non-null object
17 PaymentMethod 7043 non-null object
18 MonthlyCharges 7043 non-null float64
19 TotalCharges 7043 non-null float64
20 Churn 7043 non-null object
dtypes: float64(2), int64(2), object(17)
memory usage: 1.1+ MB
TotalCharges의 자료형이 object에서 float64로 바뀐 것을 확인할 수 있습니다.
df.describe()
지속 회원과 탈퇴 회원의 통계랑 비교
df.groupby("Churn")["customerID"].count()
Churn
No 5174
Yes 1869
Name: customerID, dtype: int64
df.Churn.value_counts().plot(kind='pie', y='Churn', figsize=(5, 5), autopct='%1.0f%%')
데이터에서 지속 회원의 수는 5,174명이며 탈퇴 회원은 1,869명입니다.
customer_stay = df[['MonthlyCharges','tenure']][df['Churn'] == 'No'] # 탈퇴 안한 회원들의 매월청구금액,개월수 평균값들
customer_stay.describe()
customer_end = df[['MonthlyCharges','tenure']][df['Churn'] == 'Yes'] # 지속하는 회원들의 매월청구금액,개월수 평균값들
customer_end.describe()
탈퇴 회원일수록 월 사용료가 평균적으로 더 높았습니다. 탈퇴 회원에 대해서 회원 기간(tenure)의 분포를 살펴봅시다. matplotlib을 사용해서 히스토그램을 작성합니다.
plt.hist(customer_end["tenure"])
클러스터링
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
# 이탈한 고객의 경우의 MonthlyCharges와 tenure열 필터링
monthlyp_and_tenure = df[['MonthlyCharges','tenure']][df['Churn'] == 'Yes']
monthlyp_and_tenure
자, 이제 두 개의 열에 대해서 클러스터링을 해줄 것입니다.
그런데 5강에서 클러스터링 전에 전체 열에 대해서 값에 정규화를 해주므로서 특정 열의 값에 좌지우지되지 않도록 해준 것 기억나시나요?
그리고 4강에서 사실 정규화 방법에는 여러가지 방법이 있다고 코드스니펫을 통해 안내를 드린 적이 있습니다.
해당 코드스니펫의 링크는 다음과 같았는데요.
해당 링크를 가보시면 알겠지만, 정규화 방법 중에는 MinMaxScaler라는 방법 또한 존재합니다.
scaler = MinMaxScaler()
monthly_and_tenure_standardized = pd.DataFrame( scaler.fit_transform(monthlyp_and_tenure) )
monthly_and_tenure_standardized.columns = ['MonthlyCharges','tenure']
monthly_and_tenure_standardized
K-means를 통해 3개의 클러스터를 만듭니다.
kmeans = KMeans(n_clusters=3, random_state=42).fit(monthly_and_tenure_standardized)
monthly_and_tenure_standardized['cluster'] = kmeans.labels_
monthly_and_tenure_standardized
monthly_and_tenure_standardized.groupby("cluster").count()
그룹1가 다른 그룹에 비해 수가 두 배 정도 많고, 그룹0이 그룹2보다는 많지만 크게 차이나지 않습니다.
클러스터링은 튜터님의 정답코드와 출력이 다르게 나온다 랜덤이기 때문에
monthly_and_tenure_standardized.groupby("cluster").mean()
결과를 보면 그룹 0은 월 사용료와 이용 기간 둘 다 짧습니다. 그룹 2는 월 사용료도 높고, 사용 기간 또한 길었구요. 그룹 1는 월 사용료는 높았지만, 사용 기간은 짧았습니다. (앞서 확인했듯이 가장 많은 수의 이탈 고객에 해당됩니다.) 그룹의 특징을 알면 그룹별로 다른 캠페인을 사용할 수 있습니다.
이제 시각화를 진행해봅시다.
강의에서 스포츠센터 고객 데이터에서는 클러스터링 시각화를 위해서 5차원을 2차원으로 줄이기 위해서 차원 축소를 사용하였지만,
현재는 특성이 2차원밖에 없으므로 굳이 차원 축소를 사용할 필요가 없습니다.
각각의 특성이 x축과 y축이 되어줄 것이기 때문입니다.
# 군집 결과에 대한 산점도
fig, ax = plt.subplots(figsize=(13,8))
plt.scatter( monthly_and_tenure_standardized['MonthlyCharges'], monthly_and_tenure_standardized['tenure'], c=monthly_and_tenure_standardized['cluster'])
plt.title('Clustering churned users by monthly Charges and tenure')
plt.xlabel('Monthly Charges')
plt.ylabel('Tenure')
plt.show()
월간 요금이 낮았던 대부분의 이탈 사용자는 매우 빠른 시간 내로 이탈했습니다. 이들은 더 낮은 금액이나 가성비가 좋은 업체로 빠르게 이동하는 것을 바랬을 수 있습니다. 이탈 사용자 중 사용 기간이 길고 낮은 가격을 가진 경우의 이탈 사용자는 매우 적습니다.
초록이 빠른 이탈자 = 가격대비 만족을 못한건가
전처리
del df["customerID"]
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7043 entries, 0 to 7042
Data columns (total 20 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 gender 7043 non-null object
1 SeniorCitizen 7043 non-null int64
2 Partner 7043 non-null object
3 Dependents 7043 non-null object
4 tenure 7043 non-null int64
5 PhoneService 7043 non-null object
6 MultipleLines 7043 non-null object
7 InternetService 7043 non-null object
8 OnlineSecurity 7043 non-null object
9 OnlineBackup 7043 non-null object
10 DeviceProtection 7043 non-null object
11 TechSupport 7043 non-null object
12 StreamingTV 7043 non-null object
13 StreamingMovies 7043 non-null object
14 Contract 7043 non-null object
15 PaperlessBilling 7043 non-null object
16 PaymentMethod 7043 non-null object
17 MonthlyCharges 7043 non-null float64
18 TotalCharges 7043 non-null float64
19 Churn 7043 non-null object
dtypes: float64(2), int64(2), object(16)
memory usage: 1.1+ MB
df
gender_map = {"Female" : 0, "Male": 1}
yes_no_map = {"Yes" : 1, "No" : 0}
df["gender"] = df["gender"].replace(gender_map)
df["Partner"] = df["Partner"].replace(yes_no_map)
df["Dependents"] = df["Dependents"].replace(yes_no_map)
df["PhoneService"] = df["PhoneService"].replace(yes_no_map)
df["PaperlessBilling"] = df["PaperlessBilling"].replace(yes_no_map)
df["Churn"] = df["Churn"].replace(yes_no_map)
현재 타입이 object이면서 값의 종류가 2개(Yes와 No)밖에 없는 경우에 대해서 전부 1과 0으로 변환.
df
바차트
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(ncols=2, nrows=2)
fig.set_size_inches(10, 10)
sns.countplot(x='gender', hue="Churn", data=df, ax=ax1).set_title('Demographic Variables: gender')
sns.countplot(x='SeniorCitizen', hue="Churn", data=df, ax=ax2).set_title('Demographic Variables: SeniorCitizen')
sns.countplot(x='Partner', hue="Churn", data=df, ax=ax3).set_title('Demographic Variables: Partner')
sns.countplot(x='Dependents', hue="Churn", data=df, ax=ax4).set_title('Demographic Variables: Dependents')
plt.tight_layout()
Boxplot
figure, (ax1, ax2) = plt.subplots(1, 2, figsize= (8, 6))
sns.boxplot(x = 'Churn', y = 'TotalCharges', data = df, ax=ax1)
sns.boxplot(x = 'Churn', y = 'MonthlyCharges', data = df, ax=ax2)
더미형 변수 추가
final_df = pd.get_dummies(df)
final_df
final_df.columns
Index(['gender', 'SeniorCitizen', 'Partner', 'Dependents', 'tenure',
'PhoneService', 'PaperlessBilling', 'MonthlyCharges', 'TotalCharges',
'Churn', 'MultipleLines_No', 'MultipleLines_No phone service',
'MultipleLines_Yes', 'InternetService_DSL',
'InternetService_Fiber optic', 'InternetService_No',
'OnlineSecurity_No', 'OnlineSecurity_No internet service',
'OnlineSecurity_Yes', 'OnlineBackup_No',
'OnlineBackup_No internet service', 'OnlineBackup_Yes',
'DeviceProtection_No', 'DeviceProtection_No internet service',
'DeviceProtection_Yes', 'TechSupport_No',
'TechSupport_No internet service', 'TechSupport_Yes', 'StreamingTV_No',
'StreamingTV_No internet service', 'StreamingTV_Yes',
'StreamingMovies_No', 'StreamingMovies_No internet service',
'StreamingMovies_Yes', 'Contract_Month-to-month', 'Contract_One year',
'Contract_Two year', 'PaymentMethod_Bank transfer (automatic)',
'PaymentMethod_Credit card (automatic)',
'PaymentMethod_Electronic check', 'PaymentMethod_Mailed check'],
dtype='object')
각종 머신 러닝 모델을 이용한 학습
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
X = final_df.drop(['Churn'], axis=1)
y = final_df['Churn']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
def get_metrics( model ):
y_pred = model.predict(X_test)
y_actual = y_test
print()
print('-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*')
print()
print('테스트 데이터에 대한 정확도 :' , accuracy_score(y_actual, y_pred)*100 , '%' )
print()
f1score = f1_score(y_actual,y_pred)
precision = precision_score(y_actual,y_pred)
recall = recall_score(y_actual,y_pred)
score_dict = { 'f1_score':[f1score], 'precision':[precision], 'recall':[recall]}
score_frame = pd.DataFrame(score_dict)
print(score_frame)
lr = LogisticRegression(C=10000, penalty='l2')
lr.fit(X_train, y_train)
print('훈련 데이터에 대한 정확도 :',lr.score(X_train,y_train)*100,'%')
get_metrics(lr)
훈련 데이터에 대한 정확도 : 80.33368832090876 %
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
테스트 데이터에 대한 정확도 : 82.11497515968772 %
f1_score precision recall
0 0.64 0.685015 0.600536
/usr/local/lib/python3.7/dist-packages/sklearn/linear_model/_logistic.py:818: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.
Increase the number of iterations (max_iter) or scale the data as shown in:
https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
extra_warning_msg=_LOGISTIC_SOLVER_CONVERGENCE_MSG,
훈련 데이터에 대한 정확도 : 81.06141285055023 %
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
테스트 데이터에 대한 정확도 : 80.34066713981547 %
f1_score precision recall
0 0.58841 0.66 0.530831
정답링크
https://colab.research.google.com/drive/1bc1kpJsFp8ix9WEr3bMR-S6zB7P8QrpX?usp=sharing
Sparta CodingClub 5강 - 통신사 고객 데이터를 이용한 종합적 데이터 분석
Colaboratory notebook
colab.research.google.com
잘모르겠다~~ 파이썬 기초를 배우고 다시 복습하는 수 밖에 없다~
'강의 > 데이터분석' 카테고리의 다른 글
데이터분석 4주차 숙제 - 📄 앞서 배운 다양한 회귀 분석을 통해서 보스턴 주택 가격을 예측해봅시다. (0) | 2022.01.30 |
---|---|
데이터분석 3주차 숙제 - 📄 붓꽃 데이터의 탐색적 데이터 분석을 진행하고, 여러가지 차트들을 그려주세요. (0) | 2022.01.27 |
데이터분석 2주차 숙제 - 📄 네이버 쇼핑 리뷰 데이터 (0) | 2022.01.26 |
데이터분석 1주차 숙제 - 📄 지니 뮤직 1~50위 곡을 스크래핑 해보세요 (0) | 2022.01.24 |