뮤트 개발일지

AIFFEL 아이펠 16일차 본문

AIFFEL

AIFFEL 아이펠 16일차

박뮤트 2022. 1. 25. 10:43

나의 첫 번째 캐글 경진대회, 무작정 따라해보기

Baseline

# 필요할 라이브러리 임포트 하기
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

import warnings
warnings.filterwarnings("ignore")

import os
from os.path import join

import pandas as pd
import numpy as np

import missingno as msno

from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import KFold, cross_val_score
import xgboost as xgb
import lightgbm as lgb

import matplotlib.pyplot as plt
import seaborn as sns
# 경로 재설정
data_dir = os.getenv('HOME')+'/aiffel/kaggle_kakr_housing/data'

train_data_path = join(data_dir, 'train.csv')
sub_data_path = join(data_dir, 'test.csv')      # 테스트, 즉 submission 시 사용할 데이터 경로
# 데이터 불러오기
data = pd.read_csv(train_data_path)
sub = pd.read_csv(sub_data_path)
print('train data dim : {}'.format(data.shape))
print('sub data dim : {}'.format(sub.shape))
>>> train data dim : (15035, 21)
>>> sub data dim : (6468, 20)
# 학습 데이터에서 라벨 제거하기
y = data['price']
del data['price']
# 데이터 전처리를 위해 학습데이터와 테스트 데이터 합치기
train_len = len(data)
data = pd.concat((data, sub), axis=0)
# 결측치 확인하기
msno.matrix(data)
# 1. id 컬럼이 결측치인지 확인합니다.
null_check = pd.isnull(data['id'])
print(null_check)

# 2. 결측치인 데이터만 뽑아냅니다.
null_data = data.loc[null_check, 'id']
null_data.head()

# 3. 결측치인 데이터의 개수를 셉니다.
print('{}: {}'.format('id', len(null_data.values)))

# 모든 컬럼에 적용하기
for c in data.columns:
    print('{} : {}'.format(c, len(data.loc[pd.isnull(data[c]), c].values)))
# id, date 컬럼 처리하기

# id 컬럼 삭제
sub_id = data['id'][train_len:]
del data['id']

# date 컬럼 필요한 부분까지만 나타내기
data['date'] = data['date'].apply(lambda x : str(x[:6]))
# 각 변수들 분포 확인
fig, ax = plt.subplots(9, 2, figsize=(12, 50))   # 가로스크롤 때문에 그래프 확인이 불편하다면 figsize의 x값을 조절해 보세요. 

# id 변수(count==0인 경우)는 제외하고 분포를 확인합니다.
count = 1
columns = data.columns
for row in range(9):
    for col in range(2):
        sns.kdeplot(data=data[columns[count]], ax=ax[row][col])
        ax[row][col].set_title(columns[count], fontsize=15)
        count += 1
        if count == 19 :
            break
# 치우친 칼럼들을 정규분포에 가깝게 만들기
skew_columns = ['bedrooms', 'sqft_living', 'sqft_lot', 'sqft_above', 'sqft_basement', 'sqft_lot15', 'sqft_living15']

for c in skew_columns:
    data[c] = np.log1p(data[c].values)

# 다시 확인
fig, ax = plt.subplots(4, 2, figsize=(12, 24))

count = 0
for row in range(4):
    for col in range(2):
        if count == 7:
            break
        sns.kdeplot(data=data[skew_columns[count]], ax=ax[row][col])
        ax[row][col].set_title(skew_columns[count], fontsize=15)
        count += 1
# 다시 학습 데이터, 테스트 데이터로 나누기
sub = data.iloc[train_len:, :]
x = data.iloc[:train_len, :]

블랜딩Blending: 여러 가지 모델을 사용해서 결과를 섞는 기법

모델은 부스팅 계열인 gboost, xgboost, lightgbm 세 가지를 사용한다.

gboost = GradientBoostingRegressor(random_state=2019)
xgboost = xgb.XGBRegressor(random_state=2019)
lightgbm = lgb.LGBMRegressor(random_state=2019)

models = [{'model':gboost, 'name':'GradientBoosting'}, {'model':xgboost, 'name':'XGBoost'},
          {'model':lightgbm, 'name':'LightGBM'}]

교차 검증

def get_cv_score(models):
    kfold = KFold(n_splits=5).get_n_splits(x.values)
    for m in models:
        CV_score = np.mean(cross_val_score(m['model'], X=x.values, y=y, cv=kfold))
        print(f"Model: {m['name']}, CV score:{CV_score:.4f}")
get_cv_score(models)

>>> Model: GradientBoosting, CV score:0.8598
>>> Model: XGBoost, CV score:0.8860
>>> Model: LightGBM, CV score:0.8819
def AveragingBlending(models, x, y, sub_x):
    for m in models : 
        m['model'].fit(x.values, y)
    
    predictions = np.column_stack([
        m['model'].predict(sub_x.values) for m in models
    ])
    return np.mean(predictions, axis=1)
    
y_pred = AveragingBlending(models, x, y, sub)
print(len(y_pred))
y_pred

* 여러 모델을 입력하면 각 모델에 대한 예측 결과를 평균 내어준다. models 딕셔너리 안에 있는 모델을 모두 x와 y로 학습시킨 뒤 predictions에 그 예측 결과값을 모아서 평균한 값을 반환한다.

# submission 파일 구성에 따라 id, price 컬럼 만들기
result = pd.DataFrame({
    'id' : sub_id, 
    'price' : y_pred
})

# submission 파일 저장
my_submission_path = join(data_dir, 'submission.csv')
result.to_csv(my_submission_path, index=False)

점수 향상을 위해 여러가지 모델 사용하기

: XGBRegressor, LGBMRegressor, GradientBoostingRegressor, RandomForestRegressor

random_state=2020 

gboost = GradientBoostingRegressor(random_state=random_state)
xgboost = XGBRegressor(random_state=random_state)
lightgbm = LGBMRegressor(random_state=random_state)
rdforest = RandomForestRegressor(random_state=random_state)

models = [gboost, xgboost, lightgbm, rdforest]
def get_scores(models, train, y):
    df = {}
    
    for model in models:
        model_name = model.__class__.__name__
        
        X_train, X_test, y_train, y_test = train_test_split(train, y, random_state=random_state, test_size=0.2)
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
        
        df[model_name] = rmse(y_test, y_pred)
        score_df = pd.DataFrame(df, index=['RMSE']).T.sort_values('RMSE', ascending=False)
            
    return score_df

하이퍼파라미터 설정하기

- 그리드 탐색 사용

from sklearn.model_selection import GridSearchCV

param_grid = {
    'n_estimators': [50, 100],
    'max_depth': [1, 10],
}

model = LGBMRegressor(random_state=random_state)

grid_model = GridSearchCV(model, param_grid=param_grid, \
                        scoring='neg_mean_squared_error', \
                        cv=5, verbose=1, n_jobs=5)

grid_model.fit(train, y)

# 모델 결과 저장
grid_model.cv_results_

# 정보 확인
params = grid_model.cv_results_['params']
params
score = grid_model.cv_results_['mean_test_score']
score

# 음수였던 점수 바꾸기
results['RMSE'] = np.sqrt(-1 * results['score'])
results

# 이름 바꾸기 (우리가 구한 RMSE는 사실 RMSLE 였다)
results = results.rename(columns={'RMSE': 'RMSLE'})
results

# RMSLE가 낮은 순서대로 정렬
results = results.sort_values('RMSLE')
results

위의 코드를 함수로 표현

# 코드 입력
def my_GridSearch(model, train, y, param_grid, verbose=2, n_jobs=5):
    # GridSearchCV 모델로 초기화
    grid_model = GridSearchCV(model, param_grid=param_grid, scoring='neg_mean_squared_error', \
                              cv=5, verbose=verbose, n_jobs=n_jobs)
    
    # 모델 fitting
    grid_model.fit(train, y)

    # 결과값 저장
    params = grid_model.cv_results_['params']
    score = grid_model.cv_results_['mean_test_score']
    
    # 데이터 프레임 생성
    results = pd.DataFrame(params)
    results['score'] = score
    
    # RMSLE 값 계산 후 정렬
    results['RMSLE'] = np.sqrt(-1 * results['score'])
    results = results.sort_values('RMSLE')

    return results

제출을 위한 함수 만들기

def save_submission(model, train, y, test, model_name, rmsle=None):
	# 모델학습
    model.fit(train, y)
    # 모델 예측
    prediction = model.predict(test)
    # 모델 스케일 되돌리기
    prediction = np.expm1(prediction)
    # 파일 가져오기
    data_dir = os.getenv('HOME')+'/aiffel/kaggle_kakr_housing/data'
    submission_path = join(data_dir, 'sample_submission.csv')
    submission = pd.read_csv(submission_path)
    # 내가 만든 값 덮어씌우기
    submission['price'] = prediction
    # csv 파일로 저장하기
    submission_csv_path = '{}/submission_{}_RMSLE_{}.csv'.format(data_dir, model_name, rmsle)
    submission.to_csv(submission_csv_path, index=False)

https://github.com/pjk7565/AIFFEL/blob/main/Exploration5/kaggle.ipynb

 

GitHub - pjk7565/AIFFEL

Contribute to pjk7565/AIFFEL development by creating an account on GitHub.

github.com

'AIFFEL' 카테고리의 다른 글

AIFFEL 아이펠 18일차  (0) 2022.01.25
AIFFEL 아이펠 17일차  (0) 2022.01.25
AIFFEL 아이펠 15일차  (0) 2022.01.24
AIFFEL 아이펠 14일차  (0) 2022.01.17
AIFFEL 아이펠 13일차  (0) 2022.01.13