#!/usr/bin/env python3
수학함수를 이용한 비선형 변환
제곱항이나 세제곱 항을 추가하면 linear regression model의 성능을 향상시킬 수 있음
한편 log, sin, exp 같은 함수를 적용하는 것도 특성 변환에 유용함
tree 모델은 max_feature(트리의 분기에서 사용될 후보 특성의 갯수)가 주요 parameter
각 모델의 특징은 이전 포스팅 참조
tree model
[1]Decision Tree -- intro, [2]Decision Tree, [3]Decision Tree Regressor
random forest
[1]Random Forest -- intro, [2]Random Forest
gradient Boosting Model
neural network
[1]Neural Network(Deep Learning)
linear model
[1]Linear Regression -- intro, [2]LinearRegression, [3]Ridge, [4]Lasso
random forest의 기본값은 'auto'로 특성 갯수의 제곱근을 나타내기때문에 나열 순서가 결과의 영향을 줄 수 있지만
decision tree와 gradient boosting tree의 기본값은 'None'으로 전체 특성을 모두 사용하기 때문에 순서에 상관없음
그러나 max_feature='auto'로 설정하면 random forest 처럼 특성의 나열 순서에 영향을 받을 수 있음
linear model과 neural network는 각 특성의 스케일과 분포에 밀접하게 연관
특성과 target값 사이에 비선형이 있다면 특히 linear regression에서는 모델을 만들기가 어려움
log와 exp함수는 데이터 스케일을 변경하여 linear model과 neural network의 성능을 올릴 수가 있음
sin, cos함수는 주기적인 패턴이 들어 있는 데이터를 다룰 때 사용
대부분의 모델은 gaussian distribution을 기본으로 하여 만들어졌기 때문에 각 특성이 gaussian distribution과 비슷할 때 최고의 성능을 나타냄
log와 exp같은 함수는 gaussian dist.모양을 만드는데 쉽고 효과적임
이런 변환은 정수형 데이터를 다룰 때 유효
카운트 데이터(음이 아닌 정수)는 특별한 통계 pattern을 따르는 경우가 많음
1. 인위적 카운트 데이터를 생성하여 비선형 변환 적용
# library import
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
# matplotlib 한글/ 축- 설정
matplotlib.rc('font', family='AppleGothic')
plt.rcParams['axes.unicode_minus']
# datasets
rnd = np.random.RandomState(seed=0) # random seed
x_org = rnd.normal(size=(1000,3)) # 정규분포
w = rnd.normal(size=3) # 정규분포
x = rnd.poisson(lam=np.exp(x_org)) # poisson distribution, lam = lambda
y = np.dot(x_org, w) # x_org(1000,3) , w(3,)이므로 (1000,)형태의 데이터가 만들어짐
print('x[:10, 0] \n{}'.format(x[:10, 0]))
print('특성 종류 \n{}'.format(np.unique(x[:, 0])))
print('특성 빈도 \n{}'.format(np.bincount(x[:,0])))
x의 개략적인 구조 확인
# visualization
_, axes = plt.subplots(1, 3)
for i, ax in enumerate(axes.ravel()):
bins = np.bincount(x[:, i])
ax.bar(range(len(bins)), bins, color='grey')
ax.hlines(y=263, xmin=-1, xmax=len(bins)+1, alpha=0.4, linestyles=':', colors='red')
ax.hlines(y=129, xmin=-1, xmax=len(bins)+1, alpha=0.4, linestyles=':', colors='red')
ax.set_xlabel('x의 {}번째 특성'.format(i+1))
ax.set_ylabel('frequency')
plt.show()
x의 특성별 histogram
>> bincount는 0부터 시작하고 큰 값의 수는 빠르게 줄어들음
2. poisson distribution에 여러가지 모델 적용
이런 종류의 분포(작은 수치는 많고, 큰값은 적은)는 많이 나타나지만 선형 모델은 이런 데이터를 잘 처리하지 못함
# library import: Ridge는 위의 링크 참조
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
# data 분할
x_train, x_test, y_train, y_test =\
train_test_split(x, y,
random_state=0, test_size=0.3)
# model 유효성 평가
for alpha in [0.001, 1, 1000]:
ridge = Ridge(alpha=alpha).fit(x_train, y_train)
print('\nalpha={}, {}의 정확도 {:.3f}'.format(alpha, ridge.__class__.__name__,ridge.score(x_test, y_test)))
alpha값에 따란 Ridge의 정확도
### 정확도가 51.3%로 좋지 못하지만, 규제를 풀수록(alpha가 커질수록) 정확도가 낮아지는 것을 확인
### log scaling
x_train_log = np.log(x_train + 1) # 0이 있으면 Inf가 나오기 때문에 1을 더함
x_test_log = np.log(x_test + 1)
### visualization
_, bins = np.histogram(x_train_log, bins=10)
_, axes = plt.subplots(1, 3)
for i, ax in enumerate(axes.ravel()):
ax.hist(x_train_log[:, i], bins=bins, color='darkblue')
ax.hlines(y=200, xmin=-1, xmax=len(bins)+1, alpha=0.4, linestyles=':', colors='red')
ax.hlines(y=100, xmin=-1, xmax=len(bins)+1, alpha=0.4, linestyles=':', colors= 'red')
ax.set_xlabel('logx의 {}번째 특성'.format(i+1))
ax.set_ylabel('frequency')
plt.show()
로그 변환 후 x 특성 값의 histogram
>> 데이터셋과 모델의 조합에 최적인 변환 방법을 찾는것은 예술에 가까운 일
이 예에서는 모든 특성이 같은 속성을 가지고 있으나 실제로 이런 경우는 드물며,
실제로는 일부 특성만 변환하거나 특성마다 모두 다르게 변환
이렇게 특성 변환은 선형 모델에서는 필수
구간 분할, 다항식, 상호작용(특성곱)은 데이터가 주어진 상황에서 모델의 성능에 큰 영향을 줄 수 있음
tree모델은 스스로 중요한 상호작용을 찾아낼 수 있고, 대부분의 경우 데이터를 변환하지 않아도 됨
SVM, K-NN, neural network모델은 선형 모델보다는 영향이 뚜렷하지 않음