Be Brave, Be Humble

빅데이터 분석기사 실기 Part5. 파이썬으로 초보 분석가 탈출하기_1 (프리렉) 본문

Statistics/Data Science

빅데이터 분석기사 실기 Part5. 파이썬으로 초보 분석가 탈출하기_1 (프리렉)

해쨔니 2022. 10. 25. 17:24

Open in Colab 누르면 코랩으로 이동 가능

 

이번 포스팅도 스파이더로 작성한 점 양해를.. 다시는 스파이더로 코딩하지 않겠습니다.

 

In [ ]:
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 21 20:51:44 2022

@author: FullSun

"""

###############################################
###   Part5. 파이썬으로 초보 분석가 탈출하기   ###
###############################################

''' ** 꿀팁[1.1]: 모듈명을 모르는 경우 ** '''
import sklearn # 패키지 가져오기
print(dir(sklearn)) # 패키지 모듈 확인하기
# ㄴ 다 안 나옴..
print(sklearn.__all__) # 이걸로 찾기

''' ** 꿀팁[1.2]: 함수명 찾기 ** '''
import sklearn.preprocessing # 모듈 가져오기
print(dir(sklearn.preprocessing)) # 함수 확인하기

''' ** 꿀팁[1.3]: 함수 파라미터 확인하기 ** '''
from sklearn.preprocessing import StandardScaler # 함수 가져오기
print(help(StandardScaler)) 

#---------------------------------------------
#             1. 데이터 분석 연습하기
#---------------------------------------------

#--------- <1-1> 데이터 탐색하기 ---------#

## 데이터 가져오기
import pandas as pd

# 변수명이 한글이라 옵션 encoding='cp949' 붙여줘야함
X_train = pd.read_csv("C:/Users/x_train.csv", encoding='cp949')
X_test = pd.read_csv("C:/Users/x_test.csv", encoding='cp949')
y_train = pd.read_csv("C:/Users/y_train.csv", encoding='cp949')
print(X_train.head())
print(X_test.head())
print(y_train.head())

''' ** 꿀팁[2]: 말 줄임표로 확인이 어려운 데이터 확인하는 법 ** '''
# 방법1)
print(X_train.head().T) # T, transepose() 함수 사용하여 행렬 바꾸기
# 방법2)
pd.options.display.max_columns = None # 전체 출력 옵션 설정
print(X_train.head())

## 행/열 확인하기
print(X_train.shape) # (3500, 10)
print(X_test.shape) # (2482, 10)
print(y_train.shape) # (3500, 2)

## 요약정보 확인하기
print(X_train.info()) #  주구매상품, 주구매지점 => 범주형

## 기초 통계량 확인하기
print(X_train.describe().T)
# 칼럼 사이에 mean값이 10^7 정도 차이가 나기 때문에 scaling 필요함

#--------- <1-2> 전처리 하기 ---------#

''' 트레이닝 데이터와 테스트 데이터 전처리
    X_train과 y_train으로 학습시키지만 X_test도 전처리 해야함 '''

## 불필요한 칼럼 삭제하기
X_train.describe().T
''' cust_id는 고객ID로 종속변수인 성별을 예측하는데 불필요 -> 삭제
    ** 단, 최종 출력 예시 보면 (cust_id, 성별)로 되어있음.
    따라서 추후 테스트 데이터의 cust_id는 최정 제출 파일에 필요하므로
    x_test_cust_id라는 변수를 별도로 저장한다!!** '''

# 테스트 데이터의 cust_id 별도 저장
X_test_cust_id = X_test['cust_id']
# cust_id 삭제
X_train = X_train.drop('cust_id', axis = 1)
# X_train = X_train.drop(columns = ['cust_id']) 같은 결과!!! 
y_train = y_train.drop('cust_id', axis = 1)
X_test = X_test.drop('cust_id', axis = 1)

##  결측치 처리하기 
print(X_train.isnull().sum()) # 환불금액: 2295
''' 환불금액이 결측치인 경우는 환불을 받은 적이 없는 것으로 예상됨.
    따라서 0으로 대치 '''
print(X_test.isnull().sum()) # 환불금액: 1611
print(y_train.isnull().sum()) # X
# 환불금 칼럼의 결측치는 0으로 대치하기
X_train['환불금액'] = X_train['환불금액'].fillna(0)
X_test['환불금액'] = X_test['환불금액'].fillna(0)
# 결과 확인
print(X_train.isnull().sum())
print(X_test.isnull().sum())

## 범주형 변수를 인코딩하기
# 주구매상품, 주구매지점
# '주구매상품', '주구매지점'에서 중복 제외한 값 확인하기
print(X_train['주구매상품'].unique())
print(X_train['주구매지점'].unique())
# '주구매상품'에서 중복 제외한 값 개수 세기
print(len(X_train['주구매상품'].unique())) # 42
print(X_train['주구매지점'].unique().size) # 24
''' 범주가 많은 경우 -> "라벨 인코딩" ''' 
# sklearn 패키지의 preprocessing 모듈에서 LabelEncoder 가져오기
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
# '주구매상품'에서 라벨인코딩 수행하고 다시 저장하기
X_train['주구매상품'] = encoder.fit_transform(X_train['주구매상품'])
# 인코딩 결과 확인하기
X_train['주구매상품'].head(10)
# '주구매상품'에 대한 라벨 인코딩 변환 순서 확인하기
print(encoder.classes_)
# 테스트 데이터도 적용
X_test['주구매상품'] = encoder.fit_transform(X_test['주구매상품'])
# '주구매지점' 라벨 인코딩
X_train['주구매지점'] = encoder.fit_transform(X_train['주구매지점'])
X_test['주구매지점'] = encoder.fit_transform(X_test['주구매지점'])

## ** 파생변수 만들기 
# 환불금액이 0보다 크면 1, 0이면 0
# 환불금액이 0보다 큰지 조건 설정
condition = X_train['환불금액'] > 0
# 조건에 맞으면 1, 아니면 0
X_train.loc[condition, '환불금액_new'] = 1
X_train.loc[~condition, '환불금액_new'] = 0
# 확인하기
print(X_train['환불금액'], X_train['환불금액_new'])
# 기존변수 삭제하기
X_train = X_train.drop(columns = '환불금액')
# 테스트 셋도 적용
condition = X_test['환불금액'] > 0
X_test.loc[condition, '환불금액_new'] = 1
X_test.loc[~condition, '환불금액_new'] = 0
print(X_test['환불금액'], X_test['환불금액_new'])
X_test = X_test.drop(columns = '환불금액')

## 표준화 크기로 변환하기 
''' 종속변수가 범주형인 경우 표준화 크기 or 로버스트 변환 '''
print(X_train.describe().T)
# 표준화 크기 변환 후 데이터 프레임으로 저장하고, X_train 칼럼명 사용하기
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = pd.DataFrame(scaler.fit_transform(X_train), columns = X_train.columns)
print(X_train.describe().T)
# ** 테스트 데이터는 transform() 만 사용하여 변환
''' train data로 학습된 Scaler()의 parameter를 통해
    test data의 feature 값들이 스케일 되는 것 '''
X_test = pd.DataFrame(scaler.transform(X_test), columns = X_test.columns)

''' 범주형 변수는 스케일링 안 하는 게 맞는데 왜 다 하는지 모르겠음
따라서, 범주형 변수는 따로 저장해두고 데이터스케일링 한 후, 
스케일링 데이터에 범주형 변수 드랍하고 원래 범주형 변수 붙이기 

X_train_cat = X_train[['환불금액_new', '주구매상품', '주구매지점']]
X_train = pd.DataFrame(scaler.fit_transform(X_train), columns = X_train.columns)
X_train.drop(columns = ['환불금액_new', '주구매상품', '주구매지점'])
X_train = pd.concat([X_train, X_train_cat], axis = 1) '''

## 상관관계 확인하기 
''' 독립변수 중에는 '금액'이라는 의미가 포함된 컬럼만 총 3개임.
    따라서 독립변수 간 상관관계를 확인하여 상관성 높은 변수 일부 제거 필요.
    corr = 0.6을 기준으로 한다 ** '''
# 총구매액, 최대구매액, 환불금액_new 간의 상관관계 확인하기
print(X_train[['총구매액', '최대구매액', '환불금액_new']].corr())
# 총구매액 & 최대구매액 corr = 0.7
# X_train셋에서 최대구매액 삭제
X_train = X_train.drop(columns = ['최대구매액'])
# X_test도 삭제
X_test = X_test.drop(columns = ['최대구매액'])

''' ** 꿀팁[3]: 데이터의 중간 결과를 수시로 백업하기 **
    X_train_backup = X_train.copy()                 '''



#--------- <1-3> 학습하고 평가하기 ---------#

## 데이터 학습시키기
''' DecisionTreeClassifier 활용하여 성별 구분해보기.
    이때 predict로 추출된 결과는 DF가 아니므로 DF 변환 필요 '''
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier() # 분류기 객체 생성
model.fit(X_train, y_train) # 학습
y_test_predicted = model.predict(X_test) # 예측
print(pd.DataFrame(y_test_predicted).head()) # 결과 보기

## 수동으로 하이퍼 파라미터 튜닝하기
''' max_depth: 트리의 깊이
    criterion: 트리노드 분기 조건. default: gini계수 '''
# 모델 객체 생성하기
model = DecisionTreeClassifier(max_depth=10, criterion='entropy',
                               random_state = 66)
# 학습하기
model.fit(X_train, y_train)
# 예측하기
y_test_predicted = model.predict(X_test)
# 결과 확인하기
print(pd.DataFrame(y_test_predicted))

''' ** GridSearchCV() 사용하지 않는 이유
    빅데이터 분석기사의 실기 제2유형은 실행 시간이 1분 이내로 제한됨.
    GridSearchCV() 사용할 경우 1분 이내로 수행될 거란 보장 없음.
    따라서 알고있는 하이퍼파라미터를 1~2가지 입력하거나,
    디폴트 모델 사용하기!!!!                                 '''

## +++++++++ Deep Dive +++++++++ ##
## GridSearchCV()로 하이퍼 파라미터 튜닝하기
''' sklearn에서 제공하는 함수로 CV와 더불어 입력된 하이퍼 파라미터의
    최적 조합을 찾아준다. 또한, GridsearchCV()는 주로 스케일링이나
    인코딩 작업과 더불어 병렬처리를 수행한다 '''

## 1) GridSearchVD()와 병렬처리 통해 빠른 결과 얻기 위한 pipeline() 가져오기
# 하이퍼 파라미터 튜닝을 위한 GridSearchCV() 함수 가져오기
from sklearn.model_selection import GridSearchCV
# 병렬처리 위한 Pipeline 함수 가져오기
from sklearn.pipeline import Pipeline

## 2) 코드 가독성을 위해 하이퍼 파라미터를 딕셔너리 형태로 정리.
##    해당 파라미터들은 모델을 대상으로 학습에 활용할 것이므로, model__ 접두사를 작성
# 하이퍼 파라미터들과 튜닝할 값 작성하기
parameters = {'model__max_depth': [3,4,5,6],
              'model__criterion': ['gini', 'entropy']}

## 3) 표준화 크기 변환과 분류기를 동시에 병렬처리 하도록 파이프라인 모델 생성
# 데이터 스케일링과 의사결정나무 분류 작업을 병렬처리하도록 모델 만들기
pipeline_model = Pipeline([('scaler', StandardScaler()),
                           ('model', DecisionTreeClassifier())])

## 4) GridSearchCV() 사용하여 생성한 pipeline_model을 입력하고
##    조합할 파라미터셋인 parameters를 주입한다.
##    교차검증으로 모델의 성능을 올리기 위해 cv옵션도 작성한다.
grid_model = GridSearchCV(pipeline_model, param_grid=parameters,
                          cv=3)

## 5) 만들어진 grid_model 모델로 학습 시킨다.
##    이때 모델학습과 동시에 스케일링이 수행되므로 이전의 데이터 스케일링
##    작업을 따로 하지 않아도 됨.
print(grid_model.fit(X_train, y_train))

## 6) 앞에서 학습시킨 grid_model에 최적의 하이퍼 파라미터로 만들어진
##    최상의 모델 추출하여 best_model에 저장
best_model = grid_model.best_estimator_

## 7) 만들어진 best_model을 활용하여 예측
y_test_predicted = best_model.predict(X_test)
print(pd.DataFrame(y_test_predicted))


## 결과 예측하기
''' 성별에 대한 확률 예측을 위해 predict_proba() 사용 '''
y_test_proba = model.predict_proba(X_test)
print(pd.DataFrame(y_test_proba))
# 최종적으로 남성 확률 추출하기
print(pd.DataFrame(y_test_proba)[1])
result = pd.DataFrame(y_test_proba)[1]

## 모델 평가하기
''' y_test값이 있어야 하지만 없으므로 train으로 해보기.. '''
# X_train에 대한 종속변수 예측하기
y_train_predicted = model.predict(X_train)
# roc 평가지표를 위한 함수 가져오기
from sklearn.metrics import roc_auc_score
# ROC 결과 확인하기
print(roc_auc_score(y_train, y_train_predicted)) # 0.69
# train데이터로 학습시켜서 train데이터로 예측하지만
# parameter설정에서 max_depth=10해서 정확도가 0.99에 도달하지는 못 함


''' 꿀팁[4]: 테스트 데이터로 모델 평가하기 **
    시간적 여유가 있어서 파라미터 튜닝할 여유가 있다면 사용할 것.
    
    데이터 학습 시키고 모델 평가 전에, 주어진 데이터를 '다시' 분리함
    X_train, y_train => X_train1, X_val1, y_train1, y_val1
    * X_test 데이터는 건들지 않고 오로지 트레이닝 셋을 이용하여
      트레이닝셋과 밸리데이션셋으로 나눔                        '''
# 데이터 분리 위한 train_test_split
from sklearn.model_selection import train_test_split
# 트레이닝, 밸리데이션 8:2
X_train1, X_val1, y_train1, y_val1 = train_test_split(X_train, y_train,
                                                     test_size=0.2, random_state=66)
# 분리된 데이터 확인
print(X_train1.shape) # (2800, 8)
print(X_val1.shape) # (700, 8)
print(y_train1.shape) # (2800,1)
print(y_val1.shape) # (700, 1)

# 의사결정 나무 모델 생성
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(max_depth=10, criterion='entropy',
                               random_state=66)
# 학습
model.fit(X_train1, y_train1)
# 예측
y_val_predicted = model.predict(X_val1)
# 평가
from sklearn.metrics import roc_auc_score
print(roc_auc_score(y_val1, y_val_predicted)) # 0.56
# 이 값을 올리기 위해 여러 시도 해볼 것.
model = DecisionTreeClassifier(max_depth=20, criterion='entropy',
                               random_state=66)
model.fit(X_train1, y_train1)
y_val_predicted = model.predict(X_val1)
print(roc_auc_score(y_val1, y_val_predicted))



#--------- <1-4> 결과 제출하기 ---------#
''' 최종 데이터는 cust_id와 y_test 예측값을 출력해야함.
    따라서 concat() 함수를 사용하여 이전에 저장한 x_test_cust_id와
    result 변수를 열기준 통합 '''
# X_test_cust_id와 result join 하기
pd.concat([X_test_cust_id, result], axis=1)
# 칼럼명 설정하기
pd.concat([X_test_cust_id, result], axis=1).rename(columns = {1:'gender'})
# 출력결과 저장하기
final = pd.concat([X_test_cust_id, result], axis=1).rename(columns = {1:'gender'})
# final을 저장하기
final.to_csv('C:/Users/12345.csv', index=True)

# + 인덱스 포함
final = pd.read_csv('C:/Users/12345.csv')
final = final.rename(columns = {'Unnamed: 0': 'index'})
final.to_csv('C:/Users/12345.csv', index=False)

''' ** 꿀팁[5]: 제출된 파일의 정상여부 확인하기 ** 
    다시 파일 읽어보기
    final = pd.read_csv('경로')
    print(final)                                '''


#---------------------------------------------
#                최종 제출 코드
#---------------------------------------------

# 라이브러리와 파일 읽기
import pandas as pd
X_train = pd.read_csv("C:/Users/x_train.csv", encoding='cp949')
X_test = pd.read_csv("C:/Users/x_test.csv", encoding='cp949')
y_train = pd.read_csv("C:/Users/y_train.csv", encoding='cp949')
# print(X_train.describe().T)
# print(X_train.info())

# 테스트셋의 cust_id 저장하기
X_test_cust_id = X_test['cust_id']
X_test = X_test.drop(columns = ['cust_id'])
X_train = X_train.drop(columns = ['cust_id'])
y_train = y_train.drop(columns = ['cust_id'])

# 결측치 처리하기
#print(X_train.isnull().sum())
X_train['환불금액'] = X_train['환불금액'].fillna(0)
X_test['환불금액'] = X_test['환불금액'].fillna(0)

# 라벨인코딩
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
X_train['주구매상품'] = encoder.fit_transform(X_train['주구매상품'])
X_train['주구매지점'] = encoder.fit_transform(X_train['주구매지점'])
X_test['주구매상품'] = encoder.fit_transform(X_test['주구매상품'])
X_test['주구매지점'] = encoder.fit_transform(X_test['주구매지점'])

# 파생변수 만들기
condition = X_train['환불금액'] > 0
X_train.loc[condition, '환불금액_new'] = 1
X_train.loc[~condition, '환불금액_new'] = 0
condition = X_test['환불금액'] > 0
X_test.loc[condition, '환불금액_new'] = 1
X_test.loc[~condition, '환불금액_new'] = 0
#print(X_train['환불금액'], X_train['환불금액_new'])
X_train = X_train.drop(columns = ['환불금액'])
X_test = X_test.drop(columns = ['환불금액'])

# 데이터 스케일링: 표준화 크기로 변환
X_train_cate = X_train[['주구매상품','주구매지점', '환불금액_new']]
X_test_cate = X_test[['주구매상품', '주구매지점', '환불금액_new']]
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = pd.DataFrame(scaler.fit_transform(X_train), columns=X_train.columns)
X_test = pd.DataFrame(scaler.transform(X_test), columns=X_test.columns)
X_train = X_train.drop(columns=['주구매상품','주구매지점', '환불금액_new'])
X_test = X_test.drop(columns=['주구매상품','주구매지점', '환불금액_new'])
X_train = pd.concat([X_train, X_train_cate], axis=1)
#print(X_test.head().T)
X_test = pd.concat([X_test, X_test_cate], axis=1)

# 불필요한 칼럼 삭제하기
print(X_train[['총구매액', '최대구매액', '환불금액_new']].corr())
X_train = X_train.drop(columns = '최대구매액')
X_test = X_test.drop(columns = '최대구매액')
#X_train_backup = X_train
#X_test_backup = X_test

# 학습용/검증용 데이터로 나누기
from sklearn.model_selection import train_test_split
X_train1, X_val1, y_train1, y_val1 = train_test_split(X_train, y_train,
                                                      test_size=0.2, random_state=66)
# print(X_train1.shape, X_val1.shape)

# 모델 학습 및 평가하기
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import roc_auc_score

model = DecisionTreeClassifier(max_depth=10, criterion='entropy',
                               random_state=66)
model.fit(X_train1, y_train1)
y_val_predicted = model.predict(X_val1)
print(roc_auc_score(y_val1, y_val_predicted))

model.fit(X_train, y_train)
y_test_predicted = model.predict(X_test)
y_test_proba = model.predict_proba(X_test) # 0:여자일 확률 1:남자일 확률
y_test_proba = pd.DataFrame(y_test_proba)[1]

# 결과 제출하기
final = pd.concat([X_test_cust_id, y_test_proba], axis=1).rename(columns = {1:'gender'})
final.to_csv('C:/Users/12345.csv', index=False)
final = pd.read_csv('C:/Users/12345.csv')
print(final.head(6))

# index포함 결과 제출하기
final = pd.concat([X_test_cust_id, y_test_proba], axis=1).rename(columns = {1:'gender'})
final.to_csv('C:/Users/12345.csv', index=True)
final = pd.read_csv('C:/Users/12345.csv')
final = final.rename(columns = {'Unnamed: 0':'index'})
final.to_csv('C:/Users/12345.csv', index=False)
final = pd.read_csv('C:/Users/12345.csv')
print(final.head(6))
Comments