분위수 회귀(Quantile Regression) with Python

2021. 7. 22. 00:13Data Science/01_Machine Learning Study

반응형

 

분위수 회귀(Quantile Regression) 소개

 

: 팀에서 공유 섹션으로 간단한 분위수 회귀(Quantile reg)를 준비

: 발표 내용 중 일부를 코드와 함께 공유하고자 함

 

 

1. 분위수 회귀(Quantile Resgression)?

 

: 분위수 회귀선형 회귀 조건이 충족되지 않을 때 사용되는 선형 회귀의 확장 버전

https://ko.wikiqube.net/wiki/Quantile_regression


분위수 회귀


 

 

: 실제로 내가 사용하는 경우는 아래와 같음

1) Robust한 결과를 내고 싶을 때

2) 이상치가 많아 이에 대한 영향을 줄인 선형 회귀선을 구하고 싶을 때

3) 점 추정이 아닌 구간추정을 통해 결과의 정확도를 높이고 싶을 때

4) 반응변수의 스프레드를 같이 살펴보고 싶을 때

5) 선형 회귀 가정이 어려울 때

6) 내 회귀선을 상대방에게 더 설득력 있게 보이고 싶을 때 

 

 

: 그림과 같이 Reg 문제를 ML/DL로 풀어야 할 때 사용할 수 있음

: 예상도착시간 등에 단순 점 추정이 아닌 구간 추정을 통해 예측 정확도를 다르게 표현이 가능


점추정이 아닌 구간 추정


 

 

2. 분위수 회귀(Quantile Regression)의 LossFunction

 

: 우리가 가장 많이 사용하는 OLS 회귀는 조건부 평균값을 모델링하는 반면 분위수 회귀조건부 분위수를 모델링

: 조건부 분위수를 모델링하기 위해 Pinball loss를 사용함


회귀/분위수 회귀 등 loss 비교


 

 

: pinball loss의 공식은 처음 봤을 때 복잡해보일 수 있지만 한줄씩 읽어보면 매우 간단함

: 0.5 보다 분위수가 클 경우, 과소 추정에 대한 penalty를 더 부여함

: 0.5 보다 분위수가 작을 경우, 과대 추정에 대한 penalty를 더 부여함



pinball loss 설명


 

 

: 결론

분위수 회귀(Quantile Reg)는 반응 변수의 조건부 분위수를 모델링 하는 모델이며 이를 위해 Pinball loss를 사용

 

 

3. 분위수 회귀(Quantile Regression) with Python

 

: 분위수 회귀는 이미 다양한 API로 구현이 되어 있음

: 가장 많이 사용하는 모델과 RF로 접근하는 방식을 파이썬으로 소개하고자 함

 

사용한 패키지

from sklearn.datasets import make_regression
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as npfrom sklearn.model_selection
import train_test_splitimport statsmodels.formula.api as smf
from lightgbm import LGBMRegressor
from sklearn.ensemble import RandomForestRegressor

 

 

데이터 만들기

x, y = make_regression( n_samples=10000, n_features=1, n_informative=1, n_targets=1, random_state=42 )
df = pd.DataFrame([x.reshape(-1), y.reshape(-1)]).T
df.columns = ['distance', 'time']
df['distance'] = df['distance'].apply(lambda x: 10 + (x +np.random.normal()))
df['time'] = df['time'].apply(lambda x: 40 + 0.2 * (x +np.random.normal()))

사용한 데이터

 

 

1) Stats Model_Quantile Reg

train_x, test_x, train_y ,test_y = train_test_split( df[['distance']], df[['time']], test_size=0.1, random_state=42, )

print(train_x.shape)
print(train_y.shape)
print(test_x.shape)
print(test_y.shape)

model_list = []
pred_dict = {}

for quantile in [0.1, 0.5, 0.9]:
    df = pd.concat([train_x, train_y], axis=1).reset_index(drop=True)
    quantile_reg = smf.quantreg('time ~ distance', df).fit(q = quantile)
    pred = quantile_reg.predict(test_x)
    pred_dict[quantile] = pred

pred_df = pd.concat(
                                    [test_x.reset_index(drop=True),
                                     pd.DataFrame(pred_dict).reset_index(drop=True),
                                     test_y.reset_index(drop=True)],
                                     axis=1,
                                     )

stats model

 

 

2) LGBM_Quantile Reg

train_x, test_x, train_y ,test_y = train_test_split( df[['distance']], df[['time']], test_size=0.1, random_state=42, )

print(train_x.shape)
print(train_y.shape)
print(test_x.shape)
print(test_y.shape)

model_list = []
pred_dict = {}

for quantile in [0.1, 0.5, 0.9]:
    clf = LGBMRegressor(objective = 'quantile', alpha = quantile)
    clf.fit(train_x, train_y)
    pred = clf.predict(test_x)
    pred_dict[quantile] = pred

pred_df = pd.concat(
                                    [test_x.reset_index(drop=True),
                                     pd.DataFrame(pred_dict).reset_index(drop=True),
                                     test_y.reset_index(drop=True)],
                                     axis=1,
                                     )

LGBM

 

 

3) RF_Quantile Reg 접근 방법

for i in range(10):
    df['x_{}'.format(i)] = df['distance'].apply(lambda x: (i+10) * 5 + (x +np.random.normal()))

train_x, test_x, train_y ,test_y = train_test_split( df[['distance']], df[['time']], test_size=0.1, random_state=42, )

print(train_x.shape)
print(train_y.shape)
print(test_x.shape)
print(test_y.shape)

model_list = []
pred_dict = {}

rf = RandomForestRegressor( n_estimators=1000, random_state=42, n_jobs=-1 )
rf.fit(train_x.values, train_y.values)

for estimator in rf.estimators_:
    pred_list.append(estimator.predict(test_x))

for quantile in [0.1, 0.5, 0.9]:
    y_pred = np.percentile(pred_list, quantile * 100, axis=0)
    pred_dict[quantile] = y_pred


pred_df = pd.concat(                                   
                                   [test_x.reset_index(drop=True),             
                                   pd.DataFrame(pred_dict).reset_index(drop=True),                 
                                   test_y.reset_index(drop=True)],                                     
                                   axis=1,                                     
                                   )

 

반응형