본문 바로가기
멋쟁이사자처럼 AIS7/오늘코드

[1108] log를 이용한 데이터 전처리, 하이퍼 파라미터 튜닝, Feature Engineering

by YeonGun M 2022. 11. 8.

0601 실습

feature 선별을 위한 EDA의 중요성

day 피처를 삭제해야 하는 이유
⇒ 데이터셋 분할이 19-20일 기준으로 진행되어 train과 test 데이터셋이 다름

Untitled


month 피처를 삭제해야 하는 이유
⇒ 월이 해마다 비슷한 값이 아니라 2배 정도 차이 납니다. 그런데 월을 넣어주면 월은 2배 정도 차이가 있음에도 오해의 소지가 있을 수 있습니다.
⇒ 같은 달인데 값이 차이가 많이 나기 때문에 혼란이 있을 수 있습니다.

Untitled


year-month 피처가 유의미한가?

Untitled


만약 month와 year을 합쳐서 새로운 피처를 만든다면, RMSLE 자체는 감소하지만 실제 competiton에서는 좋은 결과가 나오지 않는다.

cf. ordinal encoding : category type으로 변경 후 ordinal encoding

train['year-month-code'] = train['year-month'].astype('category').cat.codes
test['year-month-code'] = test['year-month'].astype('category').cat.codes

Untitled


피처 중요도룰 시각화했을 때 유의미한 값이 나오는 듯 하나, 피처 중요도란 어느 데이터 요소가 확률값 계산에 중요하게 작용을 했느냐 하는 정도를 나타내는 것이지 모델의 성능을 설명하지는 않는다. 모델의 성능은 CV를 통해 평가한다.

0602 실습

=> 모든 전처리가 0601 파일과 동일하게 진행되나 dayofweek가 추가된 점이 다르다.
판다스 공식문서 Datetime properties

train["datetime"].dt.dayofweek

과거에 했었답니다? 복습하세욧!
코로나 확진 데이터에서 요일을 구할 때, 처방내역 분석할 때 처방일자의 요일을 구할 때 코로나 확진 데이터 분석 했을 때를 기억하면 월요일은 확진수가 다른 요일에 비해 낮았는데 왜냐하면 주말에 검사를 적게 받기 때문에 화요일에 확진수가 가장 많다는 것을 실습을 통해 확인했었습니다. 처방내역은 월요일에 병원에 가장 많이 가기 때문에 월요일에 처방수가 가장 많은 것을 시각화를 해서 확인했었습니다.

log를 이용한 전처리

Untitled


왜도(skewed)가 심한 데이터에 log를 취하면 완만해져서 정규분포에 가까워질때가 있다. 다만 log를 취할 때 1을 더해주는데, 이는 1 이하의 값에에 log를 취하면 음수가 나오는 것을 방지하기 위함이다.
=> 로그함수에 지수함수(np.exp)를 취하면 원래 데이터값이 나온다(역함수 관계).

# 로그함수 적용
train["count_log1p"] = np.log(train['count'] + 1)

# 지수함수 적용
train['count_expm1']= np.exp(train["count_log1p"]) - 1

untitled



cf. train["count_log1p"] == train['count_expm1']에는 False가 섞여 나옵니다.
이는 소수점에서 반올림을 어떻게 하느냐의 차이일 수도 있고, 1.1 + 0.1 == 1.2False로 컴퓨터가 인식하는 이유일 수도 있습니다.
참고영상

Q. 왜 정규분포가 되면 머신러닝이나 딥러닝에서 좋은 성능을 낼까?
A. 값을 볼 때 한쪽에 너무 치우쳐져 있고 뾰족하다면 특성을 제대로 학습하기가 어렵기 때문에 정규분포로 되어 있다면 특성을 고르게 학습할 수 있겠죠.

Q. 왜 count에 log를 취하고 다시 지수함수로 복원을 했을까?
A. log 값으로 예측하고 예측값을 복원하기 위해서 지수함수를 사용하는 법을 배웠다.

label_name = 'count_log1p'
feature_names = ['holiday', 'workingday', 'weather', 'temp', 'atemp', 
                 'humidity', 'windspeed', 'year',  'hour', 'dayofweek']

 

Q. 실무에서는 어떤 평가지표를 사용할까?
A. 실무에서는 보통 비즈니스 평가지표를 더 많이 사용합니다. 경진대회나 실습에서 사용하는 평가지표는 모델의 성능을 측정해서 객관화 해보기 위해 사용합니다. 모델을 만드는 목적은 비즈니스 문제 해결을 위해서 입니다. 그 모델의 목적이 DAU를 올리는 것이라면 DAU를 측정하고 매출을 늘리고 싶다면 매출액이 늘어났는지, 구매자수가 늘어났는지 등을 평가하게 됩니다.

cf. DAU
DAU( Daily Active Users )는 하루 동안 해당 서비스를 이용한 순수한 이용자 수를 말한다. 보통 게임에서 해당 서비스를 얼마나 많은 사용자가 실제로 이용하고 있는지를 나타내는 지표 중에 하나로 활용한다.

Q. casual이랑 regestered 변수는 어떻게 사용할까?
A. casual은 비회원 바이크 대여 수, registered는 회원 대여 바이크 대여 수다.
이를 활용하기 위해선 회원 따로 비회원 따로 예측 하고 더해준다(회원 + 비회원 == count)
label 에 회원으로 학습하고 예측 + label에 비회원으로 학습하고 예측 == 제출 예측값
회원과 비회원을 따로 예측해서 더해주면 스코어가 약간 더 올라갑니다.

모델 생성 및 평가

  1. 랜덤 포레스트로 생성
    from sklearn.ensemble import RandomForestRegressor
    

model = RandomForestRegressor(random_state=42, n_jobs=-1)

<br></br>
2. 하이퍼 파라미터 튜닝(랜덤서치 이용)
```python
from sklearn.model_selection import RandomizedSearchCV

# param_distributions = {"max_depth" : np.random.randint(7, 20, 10),
#                        "max_features" : np.random.uniform(0.5, 1, 10)}

param_distributions = {"max_depth": np.random.randint(15, 20, 10), 
                       "max_features": np.random.uniform(0.8, 1, 10)}

reg = RandomizedSearchCV(model, 
                         param_distributions=param_distributions, 
                         scoring='neg_root_mean_squared_error',
                         n_iter=10, cv=5, n_jobs=-1,
                         verbose=2, random_state=42)

reg.fit(X_train, y_train)

Q. 왜 scoring에 'neg_root_mean_squared_error'가 들어갈까?
A. label_name에 log를 취한 count 값이 있으므로, RMSE가 RMSLE와 동일하다
다만 'neg'가 들어가서 음수로 값이 반환되는데 이에 대한 이유는 정확히 알 수 없다. 추측컨데, 정렬을 위해 앞에 음수를 붙여준 것이 아닐까 싶다. 오차를 이용한 평가지표와 반대로 Accuracy, R square score 등은 큰 값일수록 좋은 값이기 때문이다. 어찌되었든 음수값이 나오기에 neg_root_mean_squared_error 는 절댓값을 적용하였을 때 작은 값이 오차가 작은 값이다.

  1. 이후 생성된 우수 모델로 학습과 예측을 진행하고 제출한다.
  2. 점수를 보며 하이퍼 파라미터 튜닝을 반복하거나 피처 선정을 수정하는 듯 시행착오를 겪으며 점수를 올릴 수 있다.
    => 신기하게도 season(분기)는 유의미한 피처지만 month는 학습을 방해한다. 지나치게 오버피팅이 되어서 그런건지 이유는 모른다.

0701 실습 Feature Engineering

House Prices - Advanced Regression Techniques

데이터 탐색

히스토그램을 그려서 어떤 데이터를 분석하고 전처리해야할지 대략적으로 파악한다.

Untitled

결측치 탐색

피처가 너무 많으므로 아래와 같은 코드를 사용하여 결측치만 있는 피처를 확인할 수 있다.

train_null = train.isna().sum()
train_sum = train_null[train_null>0].sort_values(ascending=False)
train_na_mean = train.isnull().mean() * 100

pd.concat([train_null, train_na_mean], axis=1).loc[train_sum.index]

이상치 탐색

이상치가 있으면 overfitting 되어 일반화가 어려워진다. 아래와 같은 이상치를 어떻게 전처리해야할까?

Untitled

  1. 제거
    => train은 제거할 수 있으나 test에는 제거할 수가 없다.
  2. 평균이나 중앙값으로 대체
    => 너무 큰 값을 평균이나 중앙값으로 대체한다면 우리가 청담동 연예인이 살고 있는 집을 평균 가격으로 조정하는 것과 비슷합니다. 그래서 이렇게 조정하면 실제 값이 많이 왜곡이 될 수 있겠죠.
  3. 4분위수로 분할하여 예측
    => 이게 피처라면 가능할 수도 있는 접근법이지만, 하지만 이 값은 label 정답이라 불가능하다.

희소값 탐색

범주형 데이터의 희소값이 존재할 경우 overfitting의 우려가 존재한다. 또한 너무 희소한 행렬이 생성되기 때문에 계한에 많은 자원이 필요하다. 아에 희소값을 결측치 처리하거나 '기타' 등으로 묶어주어 one-hot-encoding의 개수를 줄여줄 수 있다.
아래의 코드를 통해 범주가 가장 많은 피처를 확인할 수 있다.

train.select_dtypes(include='object').nunique().nlargest(20)

'Neighborhood'의 고유값의 개수를 시각화해보면 아래와 같다.

untitled

댓글