티스토리 뷰
[FastCampus] 파이썬을 활용한 이커머스 데이터 분석하기¶
Ch04. 고객 이탈 예측(KNN)¶
01. 분석의 목적¶
- KNN 알고리즘으로 고객이탈(customer churn)을 예측
- Binary Classification(고객 이탈을 한다 안한다를 예측하기 때문이다.)
- 통신사 고객데이터를 이용하여 유추해 보려한다. 통신사 고객 데이터는 고객 이탈이 빈번하기 때문에 이번 주제에 알맞는 데이터이다.
02. KNN의 원리¶
KNN의 뜻은 K-Nearly-Neighbors의 약자로 새로운 데이터의 특성을 가장 가까운 데이터의 특성을 이용하여 예측하는 방식이다.
03. 파이썬 Tip - list¶
아래 코드와 같이 대괄호를 이용하여 리스트를 만든다.
x = [1,2,3]
['a','b','c']
['a', 'b', 'c']
리스트 안에 리스트도 만들 수 있다.
y = [1,2,3,[4,5]]
위 코드는 리스트가 4개 들어가 있는 형식이라 볼 수 있다.
데이터의 길이를 확인하려면 len() 메서드를 사용하면 된다.
len(x)
3
len(y)
4
my_list = [1,2,3,4,5]
my_list
[1, 2, 3, 4, 5]
appen() 메서드를 이용하면 리스트에 새로운 데이터를 추가로 넣어 줄 수 있다.
my_list.append(6)
my_list
[1, 2, 3, 4, 5, 6]
6이 추가된 것을 볼 수 있다. 문자도 넣어줄 수 있다.
my_list.append('a')
my_list
[1, 2, 3, 4, 5, 6, 'a']
다음과 같이 인덱싱도 가능하다.
my_list[-2]
6
my_list[3:]
[4, 5, 6, 'a']
리스트 안에 있는 데이터를 바꾸려면 아래와 같이 하면 된다.
my_list[0] = 'x'
my_list
['x', 2, 3, 4, 5, 6, 'a']
튜플 타입은 리스트와는 다르게 안에 있는 데이터를 바꿀 수 없다.
04. 파이썬 Tip - For, While 문¶
x = [1,2,3]
x
[1, 2, 3]
x 안에 있는 데이터 1,2,3을 차례대로 출력할 수 있는 코드를 For문을 이용해 만들어 보자.
for i in x:
print(i)
1
2
3
for i in x:
print(i+10)
11
12
13
range() 메서드를 이용하면 0부터 9까지의 일련의 숫자들이 자동으로 정렬된다. 이 메서드를 이용하면 조금 더 편리하다.
for i in range(10):
print(i)
0
1
2
3
4
5
6
7
8
9
이번엔 for문을 이용해 인덱싱을 해보자.
a = ['apple','orange','banana','melon']
b = [1,0,2]
for i in b:
print(a[i])
orange
apple
banana
while문은 for문과 비슷하지만 for문과는 다르게 조건이 만족한다면 계속해서 돌아가는 방식이다.
t = 11
while t < 10:
print('hi')
위 처럼 while문 안의 조건이 맞지 않으면 아무것도 실행되지 않는다. 조건이 맞는다면 무한루프로 계속 hi가 나오게 될 것이다. 그래서 조건이 잘 끝날 수 있도록 정해주어야 한다.
t = 0
while t < 10:
print(t)
t = t + 1
0
1
2
3
4
5
6
7
8
9
이번엔 while문을 사용하여 리스트를 만들어 보자.
a = []
b = 1
while len(a) < 10:
a.append(b)
b = b + 3
a
[1, 4, 7, 10, 13, 16, 19, 22, 25, 28]
len(a)
10
05. 모듈, 데이터 로딩 및 데이터 확인¶
먼저 필요한 모듈을 불러오자.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
data = pd.read_csv('churn.csv')
data
customerID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | ... | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | Churn | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | DSL | No | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 | No |
1 | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | DSL | Yes | ... | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.50 | No |
2 | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | DSL | Yes | ... | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 | Yes |
3 | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | DSL | Yes | ... | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 | No |
4 | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | Fiber optic | No | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 | Yes |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | Male | 0 | Yes | Yes | 24 | Yes | Yes | DSL | Yes | ... | Yes | Yes | Yes | Yes | One year | Yes | Mailed check | 84.80 | 1990.50 | No |
7039 | 2234-XADUH | Female | 0 | Yes | Yes | 72 | Yes | Yes | Fiber optic | No | ... | Yes | No | Yes | Yes | One year | Yes | Credit card (automatic) | 103.20 | 7362.90 | No |
7040 | 4801-JZAZL | Female | 0 | Yes | Yes | 11 | No | No phone service | DSL | Yes | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 29.60 | 346.45 | No |
7041 | 8361-LTMKD | Male | 1 | Yes | No | 4 | Yes | Yes | Fiber optic | No | ... | No | No | No | No | Month-to-month | Yes | Mailed check | 74.40 | 306.60 | Yes |
7042 | 3186-AJIEK | Male | 0 | No | No | 66 | Yes | No | Fiber optic | Yes | ... | Yes | Yes | Yes | Yes | Two year | Yes | Bank transfer (automatic) | 105.65 | 6844.50 | No |
7043 rows × 21 columns
data.head()
customerID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | ... | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | Churn | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | DSL | No | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 | No |
1 | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | DSL | Yes | ... | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.50 | No |
2 | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | DSL | Yes | ... | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 | Yes |
3 | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | DSL | Yes | ... | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 | No |
4 | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | Fiber optic | No | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 | Yes |
5 rows × 21 columns
컬럼이 너무 많아서 ... 으로 나오는 부분까지 모두 보려면 아래의 set_option() 메서드를 이용하여 출력하면 된다. 행을 모두 보려면 columns 대신 rows를 입력해주면 된다.
pd.set_option('display.max_columns', 30)
data.head()
customerID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | Churn | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | DSL | No | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 | No |
1 | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | DSL | Yes | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.50 | No |
2 | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | DSL | Yes | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 | Yes |
3 | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | DSL | Yes | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 | No |
4 | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 | Yes |
컬럼을 확인해 보자.
- cutomerID : 고객 ID (분석에는 크게 의미없는 데이터이다.)
- gender : 성별
- SeniorCitizen : SeniorCitizen이 아닌지 여부
- Partner : Parter 여부
- Dependents : Dependents 여부
- tenure : 얼마나 사용했는지의 대한 달의 수
- Phone Survice
- MultipleLines : 회선의 갯수
- InternetService
- OnlineSecurity
- OnlineBackup
- DeviceProtection
- TechSupport
- StreamingTV
- StreamingMovies
- Contract : 월 단위 계약인지 연 단위 계약인지의 대한 내용
- PaperlessBilling
- PaymentMethod : 결제 수단
- MonthlyCharges : 월별 금액
- TotalCharges : 총 지불한 금액
- Churn : 고객이 이탈을 했는지 안했는지의 여부 (이번 분석에서 예측할 컬럼이다.)
각 컬럼들의 정보를 알아보자.
data.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
숫자로 되어있는 데이터보단 텍스트로 되어 있는 데이터가 더 많은 것을 볼 수 있다. TotalCharges는 위의 데이터 상에선 숫자로 되어있는데 info()로 확인해 보니 텍스트 형식으로 되어 있는것을 볼 수 있다. 이것을 숫자 데이터로 바꾸어줄 필요가 있어 보인다.
pd.to_numeric(data['TotalCharges'])
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
pandas/_libs/lib.pyx in pandas._libs.lib.maybe_convert_numeric()
ValueError: Unable to parse string " "
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
<ipython-input-56-ff40986ab5f9> in <module>
----> 1 pd.to_numeric(data['TotalCharges'])
~/.local/lib/python3.6/site-packages/pandas/core/tools/numeric.py in to_numeric(arg, errors, downcast)
151 try:
152 values = lib.maybe_convert_numeric(
--> 153 values, set(), coerce_numeric=coerce_numeric
154 )
155 except (ValueError, TypeError):
pandas/_libs/lib.pyx in pandas._libs.lib.maybe_convert_numeric()
ValueError: Unable to parse string " " at position 488
488번째 데이터에 숫자가 아닌 " " 이런 데이터가 포함되어 있어 숫자 데이터로 바꿀 수 없다고 오류가 난다. 488 번째의 데이터를 확인해보자.
data.iloc[488]
customerID 4472-LVYGI
gender Female
SeniorCitizen 0
Partner Yes
Dependents Yes
tenure 0
PhoneService No
MultipleLines No phone service
InternetService DSL
OnlineSecurity Yes
OnlineBackup No
DeviceProtection Yes
TechSupport Yes
StreamingTV Yes
StreamingMovies No
Contract Two year
PaperlessBilling Yes
PaymentMethod Bank transfer (automatic)
MonthlyCharges 52.55
TotalCharges
Churn No
Name: 488, dtype: object
스페이스바로 되어 있는 이 부분을 바꾸어 주려면 replace() 메서드를 이용하여 바꾸어 줄 수 있다.
data['TotalCharges'] = data['TotalCharges'].replace(" ", "")
위이 코드와 같이 스페이스바 부분의 공백을 없애주면 숫자 데이터로 변환할 수 있다.
data['TotalCharges'] = pd.to_numeric(data['TotalCharges'])
data.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 7032 non-null float64
20 Churn 7043 non-null object
dtypes: float64(2), int64(2), object(17)
memory usage: 1.1+ MB
float64로 바뀐것을 확인할 수 있다.
data.describe()
SeniorCitizen | tenure | MonthlyCharges | TotalCharges | |
---|---|---|---|---|
count | 7043.000000 | 7043.000000 | 7043.000000 | 7032.000000 |
mean | 0.162147 | 32.371149 | 64.761692 | 2283.300441 |
std | 0.368612 | 24.559481 | 30.090047 | 2266.771362 |
min | 0.000000 | 0.000000 | 18.250000 | 18.800000 |
25% | 0.000000 | 9.000000 | 35.500000 | 401.450000 |
50% | 0.000000 | 29.000000 | 70.350000 | 1397.475000 |
75% | 0.000000 | 55.000000 | 89.850000 | 3794.737500 |
max | 1.000000 | 72.000000 | 118.750000 | 8684.800000 |
sns.distplot(data['TotalCharges'])
/home/jaeyoon89/.local/lib/python3.6/site-packages/seaborn/distributions.py:2557: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).
warnings.warn(msg, FutureWarning)
<AxesSubplot:xlabel='TotalCharges', ylabel='Density'>
06. 카테고리 변수 처리¶
위 데이터의 Gender 컬럼에서 Female과 male을 분석을 위해 0과 1로 바꾸어줄 필요가 있다. male과 female을 숫자로 바꾸어 주려면 2개의 다른 컬럼을 만들어 주어야 한다. 그리고 그 안에 0 또는 1로 채워 넣어주면 된다. 하지만 우리는 하나의 컬럼만(ex:male)을 가지고도 Gender를 구분할 수 있기 때문에 두 컬럼을 모두 가져갈 필요는 없다.
먼저 gender 컬럼의 유니크한 밸류의 갯수를 확인해 보자.
data['gender'].nunique()
2
이 2개를 get_dummies() 메서드를 이용해 바꾸어주면 컬럼 맨 끝에 Female과 male 2개의 컬럼으로 나누어진 것을 볼 수 있다. 하지만 우리는 하나의 밸류를 가지고도 gender를 구분할 수 있기 때문에 drop_first()를 True로 바꾸어 drop 시키자.
pd.get_dummies(data, columns=['gender'], drop_first = True)
customerID | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | Churn | gender_Male | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | 0 | Yes | No | 1 | No | No phone service | DSL | No | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 | No | 0 |
1 | 5575-GNVDE | 0 | No | No | 34 | Yes | No | DSL | Yes | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.50 | No | 1 |
2 | 3668-QPYBK | 0 | No | No | 2 | Yes | No | DSL | Yes | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 | Yes | 1 |
3 | 7795-CFOCW | 0 | No | No | 45 | No | No phone service | DSL | Yes | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 | No | 1 |
4 | 9237-HQITU | 0 | No | No | 2 | Yes | No | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 | Yes | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | 0 | Yes | Yes | 24 | Yes | Yes | DSL | Yes | No | Yes | Yes | Yes | Yes | One year | Yes | Mailed check | 84.80 | 1990.50 | No | 1 |
7039 | 2234-XADUH | 0 | Yes | Yes | 72 | Yes | Yes | Fiber optic | No | Yes | Yes | No | Yes | Yes | One year | Yes | Credit card (automatic) | 103.20 | 7362.90 | No | 0 |
7040 | 4801-JZAZL | 0 | Yes | Yes | 11 | No | No phone service | DSL | Yes | No | No | No | No | No | Month-to-month | Yes | Electronic check | 29.60 | 346.45 | No | 0 |
7041 | 8361-LTMKD | 1 | Yes | No | 4 | Yes | Yes | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Mailed check | 74.40 | 306.60 | Yes | 1 |
7042 | 3186-AJIEK | 0 | No | No | 66 | Yes | No | Fiber optic | Yes | No | Yes | Yes | Yes | Yes | Two year | Yes | Bank transfer (automatic) | 105.65 | 6844.50 | No | 1 |
7043 rows × 21 columns
나머지 컬럼들도 처리해야 한다. 먼저 object 타입의 컬럼들을 한번에 모아보자. 그러려면 dtype이 object인 컬럼들을 모두 불러와야 한다. 아래의 코드를 따라해보자.
data['gender'].dtype == 'O'
True
먼저 빈 리스트를 만들어 준다.
col_list = []
그 다음 append() 메서드로 하나씩 집어 넣어보자. for문을 사용하여 실행해보자.
data.columns
Index(['customerID', 'gender', 'SeniorCitizen', 'Partner', 'Dependents',
'tenure', 'PhoneService', 'MultipleLines', 'InternetService',
'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport',
'StreamingTV', 'StreamingMovies', 'Contract', 'PaperlessBilling',
'PaymentMethod', 'MonthlyCharges', 'TotalCharges', 'Churn'],
dtype='object')
for i in data.columns:
if data[i].dtype == 'O':
col_list.append(i)
col_list
['customerID',
'gender',
'Partner',
'Dependents',
'PhoneService',
'MultipleLines',
'InternetService',
'OnlineSecurity',
'OnlineBackup',
'DeviceProtection',
'TechSupport',
'StreamingTV',
'StreamingMovies',
'Contract',
'PaperlessBilling',
'PaymentMethod',
'Churn']
col_list에 있는 컬럼의 유니크한 밸류의 갯수를 확인해보자.
for i in col_list:
print(i, data[i].nunique())
customerID 7043
gender 2
Partner 2
Dependents 2
PhoneService 2
MultipleLines 3
InternetService 3
OnlineSecurity 3
OnlineBackup 3
DeviceProtection 3
TechSupport 3
StreamingTV 3
StreamingMovies 3
Contract 3
PaperlessBilling 2
PaymentMethod 4
Churn 2
customerID는 분석에 필요없기 때문에 인덱싱으로 제거해주자.
col_list = col_list[1:]
col_list
['gender',
'Partner',
'Dependents',
'PhoneService',
'MultipleLines',
'InternetService',
'OnlineSecurity',
'OnlineBackup',
'DeviceProtection',
'TechSupport',
'StreamingTV',
'StreamingMovies',
'Contract',
'PaperlessBilling',
'PaymentMethod',
'Churn']
이제 우리가 원하는 컬럼들만 모아졌다.
data = pd.get_dummies(data, columns=col_list, drop_first = True)
data
customerID | SeniorCitizen | tenure | MonthlyCharges | TotalCharges | gender_Male | Partner_Yes | Dependents_Yes | PhoneService_Yes | MultipleLines_No phone service | MultipleLines_Yes | InternetService_Fiber optic | InternetService_No | OnlineSecurity_No internet service | OnlineSecurity_Yes | ... | DeviceProtection_No internet service | DeviceProtection_Yes | TechSupport_No internet service | TechSupport_Yes | StreamingTV_No internet service | StreamingTV_Yes | StreamingMovies_No internet service | StreamingMovies_Yes | Contract_One year | Contract_Two year | PaperlessBilling_Yes | PaymentMethod_Credit card (automatic) | PaymentMethod_Electronic check | PaymentMethod_Mailed check | Churn_Yes | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | 0 | 1 | 29.85 | 29.85 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
1 | 5575-GNVDE | 0 | 34 | 56.95 | 1889.50 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
2 | 3668-QPYBK | 0 | 2 | 53.85 | 108.15 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
3 | 7795-CFOCW | 0 | 45 | 42.30 | 1840.75 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 9237-HQITU | 0 | 2 | 70.70 | 151.65 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | 0 | 24 | 84.80 | 1990.50 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | ... | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 |
7039 | 2234-XADUH | 0 | 72 | 103.20 | 7362.90 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 |
7040 | 4801-JZAZL | 0 | 11 | 29.60 | 346.45 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
7041 | 8361-LTMKD | 1 | 4 | 74.40 | 306.60 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
7042 | 3186-AJIEK | 0 | 66 | 105.65 | 6844.50 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | ... | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
7043 rows × 32 columns
07. Missing Value 확인 및 처리¶
이번엔 결측치가 있는지 확인해보자.
data.isna().sum()
customerID 0
SeniorCitizen 0
tenure 0
MonthlyCharges 0
TotalCharges 11
gender_Male 0
Partner_Yes 0
Dependents_Yes 0
PhoneService_Yes 0
MultipleLines_No phone service 0
MultipleLines_Yes 0
InternetService_Fiber optic 0
InternetService_No 0
OnlineSecurity_No internet service 0
OnlineSecurity_Yes 0
OnlineBackup_No internet service 0
OnlineBackup_Yes 0
DeviceProtection_No internet service 0
DeviceProtection_Yes 0
TechSupport_No internet service 0
TechSupport_Yes 0
StreamingTV_No internet service 0
StreamingTV_Yes 0
StreamingMovies_No internet service 0
StreamingMovies_Yes 0
Contract_One year 0
Contract_Two year 0
PaperlessBilling_Yes 0
PaymentMethod_Credit card (automatic) 0
PaymentMethod_Electronic check 0
PaymentMethod_Mailed check 0
Churn_Yes 0
dtype: int64
TotalCharges에 11개가 있는것이 확인된다. 이것을 mean이나 median으로 채워넣어 주자.
data['TotalCharges'].mean()
2283.3004408418656
data['TotalCharges'].median()
1397.475
평균과 중간값이 차이가 많이나서 distplot으로 분포를 확인해보자.
sns.distplot(data['TotalCharges'])
/home/jaeyoon89/.local/lib/python3.6/site-packages/seaborn/distributions.py:2557: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).
warnings.warn(msg, FutureWarning)
<AxesSubplot:xlabel='TotalCharges', ylabel='Density'>
mean값을 쓰면 너무 크기 때문에 이번엔 median 값을 결측치에 채워 넣어주는것이 좋아보인다.
data['TotalCharges'] = data['TotalCharges'].fillna(data['TotalCharges'].median())
data.isna().sum()
customerID 0
SeniorCitizen 0
tenure 0
MonthlyCharges 0
TotalCharges 0
gender_Male 0
Partner_Yes 0
Dependents_Yes 0
PhoneService_Yes 0
MultipleLines_No phone service 0
MultipleLines_Yes 0
InternetService_Fiber optic 0
InternetService_No 0
OnlineSecurity_No internet service 0
OnlineSecurity_Yes 0
OnlineBackup_No internet service 0
OnlineBackup_Yes 0
DeviceProtection_No internet service 0
DeviceProtection_Yes 0
TechSupport_No internet service 0
TechSupport_Yes 0
StreamingTV_No internet service 0
StreamingTV_Yes 0
StreamingMovies_No internet service 0
StreamingMovies_Yes 0
Contract_One year 0
Contract_Two year 0
PaperlessBilling_Yes 0
PaymentMethod_Credit card (automatic) 0
PaymentMethod_Electronic check 0
PaymentMethod_Mailed check 0
Churn_Yes 0
dtype: int64
위와 같이 결측치가 모두 채워졌다.
08. Scaling¶
데이터에서 스케일은 데이터 값의 크기라고 생각하면 된다. 이 스케일이 다르면 분석에 큰 지장을 준다. 예를 들면 월급과 몸무게만 비교해 보아도 스케일이 많이 다르다는 것을 알 수 있다.
스케일링을 위한 모듈을 불러오자.
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
스케일러를 사용하는 방법은 훈련 세트로 학습하고 테스트 데이터로 예측하는 모습과 비슷하다. 하지만 스케일러는 훈련 데이터와 테스트 데이터를 별도로 만들지 않고 기존 데이터로 학습을 시킨 뒤 학습된 값을 통해 데이터를 변형 시켜준다.
1. minmax 스케일러¶
minmax = MinMaxScaler()
customerID 컬럼은 string 형식이라 drop 시켜준다.
data.drop('customerID', axis = 1, inplace=True)
data.head(3)
SeniorCitizen | tenure | MonthlyCharges | TotalCharges | gender_Male | Partner_Yes | Dependents_Yes | PhoneService_Yes | MultipleLines_No phone service | MultipleLines_Yes | InternetService_Fiber optic | InternetService_No | OnlineSecurity_No internet service | OnlineSecurity_Yes | OnlineBackup_No internet service | ... | DeviceProtection_No internet service | DeviceProtection_Yes | TechSupport_No internet service | TechSupport_Yes | StreamingTV_No internet service | StreamingTV_Yes | StreamingMovies_No internet service | StreamingMovies_Yes | Contract_One year | Contract_Two year | PaperlessBilling_Yes | PaymentMethod_Credit card (automatic) | PaymentMethod_Electronic check | PaymentMethod_Mailed check | Churn_Yes | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 29.85 | 29.85 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
1 | 0 | 34 | 56.95 | 1889.50 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
2 | 0 | 2 | 53.85 | 108.15 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
3 rows × 31 columns
minmax.fit(data)
MinMaxScaler()
mixmax에 fit 메서드로 data를 넣어준다.
scaled_data = minmax.transform(data)
data.columns
Index(['SeniorCitizen', 'tenure', 'MonthlyCharges', 'TotalCharges',
'gender_Male', 'Partner_Yes', 'Dependents_Yes', 'PhoneService_Yes',
'MultipleLines_No phone service', 'MultipleLines_Yes',
'InternetService_Fiber optic', 'InternetService_No',
'OnlineSecurity_No internet service', 'OnlineSecurity_Yes',
'OnlineBackup_No internet service', 'OnlineBackup_Yes',
'DeviceProtection_No internet service', 'DeviceProtection_Yes',
'TechSupport_No internet service', 'TechSupport_Yes',
'StreamingTV_No internet service', 'StreamingTV_Yes',
'StreamingMovies_No internet service', 'StreamingMovies_Yes',
'Contract_One year', 'Contract_Two year', 'PaperlessBilling_Yes',
'PaymentMethod_Credit card (automatic)',
'PaymentMethod_Electronic check', 'PaymentMethod_Mailed check',
'Churn_Yes'],
dtype='object')
보기 좋게 데이터프레임 형식으로 바꾸어주자.
pd.DataFrame(scaled_data, columns = data.columns)
SeniorCitizen | tenure | MonthlyCharges | TotalCharges | gender_Male | Partner_Yes | Dependents_Yes | PhoneService_Yes | MultipleLines_No phone service | MultipleLines_Yes | InternetService_Fiber optic | InternetService_No | OnlineSecurity_No internet service | OnlineSecurity_Yes | OnlineBackup_No internet service | ... | DeviceProtection_No internet service | DeviceProtection_Yes | TechSupport_No internet service | TechSupport_Yes | StreamingTV_No internet service | StreamingTV_Yes | StreamingMovies_No internet service | StreamingMovies_Yes | Contract_One year | Contract_Two year | PaperlessBilling_Yes | PaymentMethod_Credit card (automatic) | PaymentMethod_Electronic check | PaymentMethod_Mailed check | Churn_Yes | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | 0.013889 | 0.115423 | 0.001275 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 |
1 | 0.0 | 0.472222 | 0.385075 | 0.215867 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
2 | 0.0 | 0.027778 | 0.354229 | 0.010310 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 |
3 | 0.0 | 0.625000 | 0.239303 | 0.210241 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
4 | 0.0 | 0.027778 | 0.521891 | 0.015330 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 0.0 | 0.333333 | 0.662189 | 0.227521 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 |
7039 | 0.0 | 1.000000 | 0.845274 | 0.847461 | 0.0 | 1.0 | 1.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 |
7040 | 0.0 | 0.152778 | 0.112935 | 0.037809 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 |
7041 | 1.0 | 0.055556 | 0.558706 | 0.033210 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 |
7042 | 0.0 | 0.916667 | 0.869652 | 0.787641 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
7043 rows × 31 columns
minmax 스케일러를 사용하면 0 ~ 1 사이의 값으로 스케일이 바뀐다. 0과 1로 되어있는 컬럼들은 그대로 나오는 것을 볼 수 있다.
2.standard 스케일러¶
standard = StandardScaler()
스케일링을 할 때는 종속변수는 빼고 스케일링을 해주는 것이 좋다. 종속변수는 영향을 받지 않고 예측이 되어야 하기 때문이다.
standard.fit(data.drop('Churn_Yes', axis = 1))
StandardScaler()
standard_st = standard.transform(data.drop('Churn_Yes', axis = 1))
pd.DataFrame(standard_st, columns = data.drop('Churn_Yes', axis = 1).columns)
SeniorCitizen | tenure | MonthlyCharges | TotalCharges | gender_Male | Partner_Yes | Dependents_Yes | PhoneService_Yes | MultipleLines_No phone service | MultipleLines_Yes | InternetService_Fiber optic | InternetService_No | OnlineSecurity_No internet service | OnlineSecurity_Yes | OnlineBackup_No internet service | OnlineBackup_Yes | DeviceProtection_No internet service | DeviceProtection_Yes | TechSupport_No internet service | TechSupport_Yes | StreamingTV_No internet service | StreamingTV_Yes | StreamingMovies_No internet service | StreamingMovies_Yes | Contract_One year | Contract_Two year | PaperlessBilling_Yes | PaymentMethod_Credit card (automatic) | PaymentMethod_Electronic check | PaymentMethod_Mailed check | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | -0.439916 | -1.277445 | -1.160323 | -0.994242 | -1.009559 | 1.034530 | -0.654012 | -3.054010 | 3.054010 | -0.854176 | -0.885660 | -0.525927 | -0.525927 | -0.633933 | -0.525927 | 1.378241 | -0.525927 | -0.723968 | -0.525927 | -0.639439 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | -0.514249 | -0.562975 | 0.829798 | -0.525047 | 1.406418 | -0.544807 |
1 | -0.439916 | 0.066327 | -0.259629 | -0.173244 | 0.990532 | -0.966622 | -0.654012 | 0.327438 | -0.327438 | -0.854176 | -0.885660 | -0.525927 | -0.525927 | 1.577454 | -0.525927 | -0.725563 | -0.525927 | 1.381277 | -0.525927 | -0.639439 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | 1.944582 | -0.562975 | -1.205113 | -0.525047 | -0.711026 | 1.835513 |
2 | -0.439916 | -1.236724 | -0.362660 | -0.959674 | 0.990532 | -0.966622 | -0.654012 | 0.327438 | -0.327438 | -0.854176 | -0.885660 | -0.525927 | -0.525927 | 1.577454 | -0.525927 | 1.378241 | -0.525927 | -0.723968 | -0.525927 | -0.639439 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | -0.514249 | -0.562975 | 0.829798 | -0.525047 | -0.711026 | 1.835513 |
3 | -0.439916 | 0.514251 | -0.746535 | -0.194766 | 0.990532 | -0.966622 | -0.654012 | -3.054010 | 3.054010 | -0.854176 | -0.885660 | -0.525927 | -0.525927 | 1.577454 | -0.525927 | -0.725563 | -0.525927 | 1.381277 | -0.525927 | 1.563872 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | 1.944582 | -0.562975 | -1.205113 | -0.525047 | -0.711026 | -0.544807 |
4 | -0.439916 | -1.236724 | 0.197365 | -0.940470 | -1.009559 | -0.966622 | -0.654012 | 0.327438 | -0.327438 | -0.854176 | 1.129102 | -0.525927 | -0.525927 | -0.633933 | -0.525927 | -0.725563 | -0.525927 | -0.723968 | -0.525927 | -0.639439 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | -0.514249 | -0.562975 | 0.829798 | -0.525047 | 1.406418 | -0.544807 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | -0.439916 | -0.340876 | 0.665992 | -0.128655 | 0.990532 | 1.034530 | 1.529024 | 0.327438 | -0.327438 | 1.170719 | -0.885660 | -0.525927 | -0.525927 | 1.577454 | -0.525927 | -0.725563 | -0.525927 | 1.381277 | -0.525927 | 1.563872 | -0.525927 | 1.265612 | -0.525927 | 1.256171 | 1.944582 | -0.562975 | 0.829798 | -0.525047 | -0.711026 | 1.835513 |
7039 | -0.439916 | 1.613701 | 1.277533 | 2.243151 | -1.009559 | 1.034530 | 1.529024 | 0.327438 | -0.327438 | 1.170719 | 1.129102 | -0.525927 | -0.525927 | -0.633933 | -0.525927 | 1.378241 | -0.525927 | 1.381277 | -0.525927 | -0.639439 | -0.525927 | 1.265612 | -0.525927 | 1.256171 | 1.944582 | -0.562975 | 0.829798 | 1.904590 | -0.711026 | -0.544807 |
7040 | -0.439916 | -0.870241 | -1.168632 | -0.854469 | -1.009559 | 1.034530 | 1.529024 | -3.054010 | 3.054010 | -0.854176 | -0.885660 | -0.525927 | -0.525927 | 1.577454 | -0.525927 | -0.725563 | -0.525927 | -0.723968 | -0.525927 | -0.639439 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | -0.514249 | -0.562975 | 0.829798 | -0.525047 | 1.406418 | -0.544807 |
7041 | 2.273159 | -1.155283 | 0.320338 | -0.872062 | 0.990532 | 1.034530 | -0.654012 | 0.327438 | -0.327438 | 1.170719 | 1.129102 | -0.525927 | -0.525927 | -0.633933 | -0.525927 | -0.725563 | -0.525927 | -0.723968 | -0.525927 | -0.639439 | -0.525927 | -0.790132 | -0.525927 | -0.796070 | -0.514249 | -0.562975 | 0.829798 | -0.525047 | -0.711026 | 1.835513 |
7042 | -0.439916 | 1.369379 | 1.358961 | 2.014288 | 0.990532 | -0.966622 | -0.654012 | 0.327438 | -0.327438 | -0.854176 | 1.129102 | -0.525927 | -0.525927 | 1.577454 | -0.525927 | -0.725563 | -0.525927 | 1.381277 | -0.525927 | 1.563872 | -0.525927 | 1.265612 | -0.525927 | 1.256171 | -0.514249 | 1.776278 | 0.829798 | -0.525047 | -0.711026 | -0.544807 |
7043 rows × 30 columns
standard 스케일러를 사용하면 이진 밸류들이 0 또는 1로 나오지 않는다.
3.Robust 스케일러¶
rob = RobustScaler()
rob.fit(data.drop('Churn_Yes', axis = 1))
RobustScaler()
scaled_rob = rob.transform(data.drop('Churn_Yes', axis = 1))
pd.DataFrame(scaled_rob, columns = data.drop('Churn_Yes', axis = 1).columns)
SeniorCitizen | tenure | MonthlyCharges | TotalCharges | gender_Male | Partner_Yes | Dependents_Yes | PhoneService_Yes | MultipleLines_No phone service | MultipleLines_Yes | InternetService_Fiber optic | InternetService_No | OnlineSecurity_No internet service | OnlineSecurity_Yes | OnlineBackup_No internet service | OnlineBackup_Yes | DeviceProtection_No internet service | DeviceProtection_Yes | TechSupport_No internet service | TechSupport_Yes | StreamingTV_No internet service | StreamingTV_Yes | StreamingMovies_No internet service | StreamingMovies_Yes | Contract_One year | Contract_Two year | PaperlessBilling_Yes | PaymentMethod_Credit card (automatic) | PaymentMethod_Electronic check | PaymentMethod_Mailed check | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | -0.608696 | -0.745170 | -0.404100 | -1.0 | 1.0 | 0.0 | -1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
1 | 0.0 | 0.108696 | -0.246550 | 0.145381 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | -1.0 | 0.0 | 0.0 | 1.0 |
2 | 0.0 | -0.586957 | -0.303588 | -0.380964 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
3 | 0.0 | 0.347826 | -0.516099 | 0.130977 | 0.0 | 0.0 | 0.0 | -1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | -1.0 | 0.0 | 0.0 | 0.0 |
4 | 0.0 | -0.586957 | 0.006440 | -0.368111 | -1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 0.0 | -0.108696 | 0.265869 | 0.175224 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
7039 | 0.0 | 0.934783 | 0.604416 | 1.762637 | -1.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
7040 | 0.0 | -0.391304 | -0.749770 | -0.310552 | -1.0 | 1.0 | 1.0 | -1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
7041 | 1.0 | -0.543478 | 0.074517 | -0.322327 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
7042 | 0.0 | 0.804348 | 0.649494 | 1.609463 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
7043 rows × 30 columns
scaled_data = pd.DataFrame(scaled_data, columns = data.columns)
scaled_data
SeniorCitizen | tenure | MonthlyCharges | TotalCharges | gender_Male | Partner_Yes | Dependents_Yes | PhoneService_Yes | MultipleLines_No phone service | MultipleLines_Yes | InternetService_Fiber optic | InternetService_No | OnlineSecurity_No internet service | OnlineSecurity_Yes | OnlineBackup_No internet service | ... | DeviceProtection_No internet service | DeviceProtection_Yes | TechSupport_No internet service | TechSupport_Yes | StreamingTV_No internet service | StreamingTV_Yes | StreamingMovies_No internet service | StreamingMovies_Yes | Contract_One year | Contract_Two year | PaperlessBilling_Yes | PaymentMethod_Credit card (automatic) | PaymentMethod_Electronic check | PaymentMethod_Mailed check | Churn_Yes | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | 0.013889 | 0.115423 | 0.001275 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 |
1 | 0.0 | 0.472222 | 0.385075 | 0.215867 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
2 | 0.0 | 0.027778 | 0.354229 | 0.010310 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 |
3 | 0.0 | 0.625000 | 0.239303 | 0.210241 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
4 | 0.0 | 0.027778 | 0.521891 | 0.015330 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 0.0 | 0.333333 | 0.662189 | 0.227521 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 |
7039 | 0.0 | 1.000000 | 0.845274 | 0.847461 | 0.0 | 1.0 | 1.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 |
7040 | 0.0 | 0.152778 | 0.112935 | 0.037809 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 |
7041 | 1.0 | 0.055556 | 0.558706 | 0.033210 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 |
7042 | 0.0 | 0.916667 | 0.869652 | 0.787641 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
7043 rows × 31 columns
이번 분석에서는 mixmax 스케일러를 사용한 scaled_data를 사용할 것이다.
09. KNN 모델 만들기¶
데이터를 훈련 세트와 테스트 세트로 나누기위한 모듈 및 코드를 입력하자.
from sklearn.model_selection import train_test_split
X = scaled_data.drop('Churn_Yes', axis = 1 )
y = scaled_data['Churn_Yes']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state=100)
KNN 머신러닝을 사용하기 위한 다음 코드를 입력하자.
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 10)
n_neighbors = 10 는 주변의 5개의 데이터를 바탕으로 새로운 데이터의 클래스를 결정한다는 의미이다.
knn.fit(X_train, y_train)
KNeighborsClassifier(n_neighbors=10)
pred = knn.predict(X_test)
pd.DataFrame(pred, y_test)
0 | |
---|---|
Churn_Yes | |
0.0 | 0.0 |
0.0 | 0.0 |
0.0 | 0.0 |
0.0 | 0.0 |
0.0 | 0.0 |
... | ... |
1.0 | 1.0 |
0.0 | 0.0 |
0.0 | 0.0 |
0.0 | 0.0 |
0.0 | 0.0 |
2113 rows × 1 columns
이렇게 출력하면 y_test 값이 인덱스로 가기 때문에 딕셔너리라는 데이터 포맷을 이용하여 보기좋게 다시 출력해보자.
pd.DataFrame({'acutal_value' : y_test, 'pred_value' : pred})
acutal_value | pred_value | |
---|---|---|
4880 | 0.0 | 0.0 |
1541 | 0.0 | 0.0 |
1289 | 0.0 | 0.0 |
5745 | 0.0 | 0.0 |
4873 | 0.0 | 0.0 |
... | ... | ... |
1285 | 1.0 | 1.0 |
5092 | 0.0 | 0.0 |
5837 | 0.0 | 0.0 |
3597 | 0.0 | 0.0 |
3625 | 0.0 | 0.0 |
2113 rows × 2 columns
pd.DataFrame({'acutal_value' : y_test, 'pred_value' : pred}).head(30)
acutal_value | pred_value | |
---|---|---|
4880 | 0.0 | 0.0 |
1541 | 0.0 | 0.0 |
1289 | 0.0 | 0.0 |
5745 | 0.0 | 0.0 |
4873 | 0.0 | 0.0 |
4168 | 0.0 | 0.0 |
1557 | 0.0 | 0.0 |
2892 | 0.0 | 0.0 |
664 | 0.0 | 0.0 |
1588 | 0.0 | 0.0 |
1338 | 1.0 | 0.0 |
6000 | 0.0 | 0.0 |
2310 | 0.0 | 0.0 |
3294 | 1.0 | 1.0 |
290 | 1.0 | 1.0 |
2505 | 0.0 | 0.0 |
3171 | 0.0 | 0.0 |
1366 | 1.0 | 1.0 |
6560 | 0.0 | 0.0 |
2420 | 0.0 | 0.0 |
5210 | 1.0 | 0.0 |
2836 | 0.0 | 1.0 |
1325 | 1.0 | 1.0 |
4900 | 1.0 | 0.0 |
6311 | 0.0 | 0.0 |
1025 | 0.0 | 0.0 |
2031 | 0.0 | 0.0 |
4459 | 1.0 | 1.0 |
5324 | 0.0 | 0.0 |
3441 | 0.0 | 0.0 |
10. 모델을 활용하여 예측하고 평가하기¶
예측을 위한 모듈을 불러오자.
from sklearn.metrics import accuracy_score, confusion_matrix
accuracy_score(y_test, pred)
0.7581637482252721
confusion_matrix(y_test, pred)
array([[1353, 194],
[ 317, 249]])
생각보다 에러가 많이 나왔다. 그럼 어떻게 하면 최적의 neighbors 갯수를 정의할 수 있을까? for문을 이용해 neighbors의 갯수를 1 ~ 100 까지 넣어보자.
error_list = []
for i in range(1,101):
knn = KNeighborsClassifier(n_neighbors = i)
knn.fit(X_train, y_train)
pred = knn.predict(X_test)
error_list.append(accuracy_score(y_test, pred))
error_list
[0.7136772361571225,
0.7491717936583058,
0.7439659252247989,
0.7557974443918599,
0.7482252721249408,
0.7581637482252721,
0.7458589682915286,
0.759110269758637,
0.7529578797917653,
0.7581637482252721,
0.7624230951254141,
0.7610033128253668,
0.7600567912920019,
0.7671557027922385,
0.7662091812588736,
0.7681022243256034,
0.7690487458589683,
0.7728348319924279,
0.7681022243256034,
0.7723615712257453,
0.7681022243256034,
0.7714150496923805,
0.7699952673923331,
0.7652626597255088,
0.767628963558921,
0.7714150496923805,
0.7733080927591103,
0.7728348319924279,
0.7733080927591103,
0.7714150496923805,
0.7699952673923331,
0.767628963558921,
0.7709417889256981,
0.7704685281590156,
0.7742546142924751,
0.7737813535257927,
0.7733080927591103,
0.77520113582584,
0.7718883104590629,
0.7737813535257927,
0.7723615712257453,
0.7775674396592522,
0.7766209181258874,
0.7747278750591576,
0.7756743965925225,
0.7766209181258874,
0.7775674396592522,
0.7775674396592522,
0.7742546142924751,
0.7709417889256981,
0.7714150496923805,
0.7756743965925225,
0.77520113582584,
0.780407004259347,
0.7742546142924751,
0.7770941788925698,
0.7761476573592049,
0.77520113582584,
0.7747278750591576,
0.7699952673923331,
0.7704685281590156,
0.7695220066256507,
0.7709417889256981,
0.7671557027922385,
0.7690487458589683,
0.7681022243256034,
0.7709417889256981,
0.7728348319924279,
0.7709417889256981,
0.7695220066256507,
0.7742546142924751,
0.7714150496923805,
0.7709417889256981,
0.7718883104590629,
0.7690487458589683,
0.7723615712257453,
0.7718883104590629,
0.7742546142924751,
0.7718883104590629,
0.7723615712257453,
0.7733080927591103,
0.7690487458589683,
0.7709417889256981,
0.7714150496923805,
0.7685754850922859,
0.7652626597255088,
0.7695220066256507,
0.7685754850922859,
0.7681022243256034,
0.7709417889256981,
0.7690487458589683,
0.7699952673923331,
0.7685754850922859,
0.7718883104590629,
0.7666824420255561,
0.7690487458589683,
0.767628963558921,
0.7695220066256507,
0.7681022243256034,
0.7690487458589683]
이것을 시각화 해보자.
plt.figure(figsize=(20,10))
sns.lineplot(x = range(1,101), y = error_list, marker = 'o', markersize=10, markerfacecolor='red')
<AxesSubplot:>
위 그래프로 n_neighbors가 어느정도일 때 accuracy 스코어가 가장 높은지 대략적으로 볼 수 있다. 코딩을 통해 가장 최고점의 포인트의 위치를 알아보자.
max(error_list)
0.780407004259347
error_list.index(max(error_list))
53
인덱스는 0부터 시작하기 때문에 53이라는 숫자가 나왔지만 실제로는 54번째가 가장 큰 accuracy가 나왔다는 것을 알 수 있다.
그리고 다음과 같이 넘파이를 이용하면 좀 더 쉽게 max값과 min 값을 알 수 있다.
np.array(error_list).argmax()
53
54번째가 가장 큰 accuray가 나왔기 때문에 n_neighbors에 54를 넣어 모델링을 다시 해보자.
knn = KNeighborsClassifier(n_neighbors = 54)
knn.fit(X_train, y_train)
KNeighborsClassifier(n_neighbors=54)
pred = knn.predict(X_test)
accuracy_score(y_test, pred)
0.780407004259347
confusion_matrix(y_test, pred)
array([[1332, 215],
[ 249, 317]])
n_neighbors를 5로 했을때 보다 정확도가 조금 더 좋아진 것을 볼 수 있다.
출처 : 패스트캠퍼스
'패스트캠퍼스 스터디' 카테고리의 다른 글
패스트캠퍼스study(ch.03 광고 반응률 예측) (0) | 2021.06.14 |
---|---|
패스트캠퍼스study(ch.02 고객별 연간 지출액 예측) (0) | 2021.06.09 |