'Apache MADlib을 활용한 훈련 검증 셋 분할 (split training test set using MADlib)'에 해당되는 글 1건

  1. 2020.04.12 [Greenplum & PostgreSQL] MADlib 을 활용한 그룹별 선형회귀모형 분산병렬 적합 및 예측

지난번 포스팅에서는 Greenplum, PostgreSQL DB에서 PL/R을 활용하여 In-DB 에서 그룹별 회귀모형 (분산 병렬) 적합 및 예측하는 방법(https://rfriend.tistory.com/529)을 소개하였습니다. 


이번 포스팅에서는 동일한 abalone 데이터셋으로 Apache MADlib (https://madlib.apache.org/) 을 사용하여 그룹별 회귀모형을 분산 병렬 적합 및 예측하는 방법을 소개하겠습니다. 


1. Apache MADlib 소개

2. web site에서 abalone 데이터셋 가져와서 table 만들기

3. 훈련, 검증 데이터 분할 (split abalone dataset into training and test set)

4. 성별 그룹별 선형회귀모형 적합 (training linear regression models by 'sex' groups')

5. 성별 그룹별 선형회귀모형 회귀계수 조회 (select coefficients per variables by 'sex' groups)

6. 성별 그룹별 선형회귀모형을 이용하여 예측 (prediction by 'sex' groups)



  1. Apache MADlib 소개


[ Apache MADlib: Big Data Machine Learning in SQL for PostgreSQL and Greenplum DB ]


Apache MADlib 은 PostgreSQL, Greenplum Database 에서 SQL 언어로 대용량 빅데이터에 대해 In-DB 기계학습, 통계분석, 그래프 분석을 할 수 있는 Apache project 의 top level 오픈 소스 라이브러리입니다. 


 Apache MADlib은 2011년 EMC/Greenplum 아키텍트와 캘리포니아 버클리 대학교(university of California, Berkeley)의 Joe Hellerstein 교수가 같이 오픈소스 프로젝트로 시작하였으며, Berkeley 대학교 외에 Stanfoard 대학교, Wisconsin 대학교, Florida 대학교 등이 같이 Apache MADlib Project에 참여하고 있습니다. 


Apache MADlib은 아래와 같이 지도학습, 비지도학습, 그래프, 통계, 시계열분석, 샘플링 및 모델 선택, 데이터 유형 변환 등의 다양한 기능의 함수를 제공합니다. 


[ Apache MADlib Functions ]


Apache MADlib은 core engine이 C++로 되어있어서 굉장히 빠릅니다. 추상적인 고수준 언어는 Python으로 되어 있고, 사용자는 SQL로 함수를 실행시키므로 SQL을 알고 있는 사용자라면 쉽고 빠르게 사용할 수 있습니다. 


모든 데이터 전처리 및 분석이 In-DB에서 이루어지므로 데이터의 In/Out이 없으며, 수백테라~페타바이트급의 대용량도  (Greenplum의 경우) 분산 병렬처리할 수 있으므로 빅데이터를 다루어서 모델링을 신속하게 해야 하는 경우에 적합합니다. 


[ Reference of Apache MADlib ]

- Open source: https://github.com/apache/madlib

- Downloads and Documents: http://madlib.apache.org

- Wiki: https://cwiki.apache.org/confluence/display/MADLIB

- Greenplum DB에 MADlib 설치https://gpdb.docs.pivotal.io/550/ref_guide/extensions/madlib.html




  2. web site에서 abalone 데이터셋 가져와서 table 만들기


UC Irvine Machine Learning Repository 에 공개된 abalone 데이터셋을 가져와서 public schema에 external table을 만들고, 이로부터 성(sex)별 칼럼을 기준으로 분산해서 저장하여 테이블을 만들어보겠습니다 (Greenplum DB 기준). 별로 어렵거나 특별한 것은 없으므로 추가 설명은 생략합니다. 



---------------------------------

-- Linear Regression in Parallel 

-- using Apache MADlib

---------------------------------


-- Dataset for example: abalone dataset from the UC Irvine Machine Learning Repository

-- URL: http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data

-- Create an external web table

DROP EXTERNAL TABLE IF EXISTS abalone_external;

CREATE EXTERNAL WEB TABLE abalone_external(

sex text 

, length float8

, diameter float8

, height float8

, whole_weight float8

, shucked_weight float8

, viscera_weight float8

, shell_weight float8

, rings integer -- target variable to predict

) LOCATION('http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data') 

FORMAT 'CSV' 

(null as '?');



-- Create a table of abalone

DROP TABLE IF EXISTS abalone;

CREATE TABLE abalone AS 

SELECT * FROM abalone_external

DISTRIBUTED BY (sex);


-- Viewing data distribution

SELECT gp_segment_id, COUNT(*) AS row_cnt

FROM abalone

GROUP BY gp_segment_id;



-- Check data

SELECT * FROM abalone LIMIT 5;




SELECT sex, COUNT(*) FROM abalone GROUP BY sex; 






  3. 훈련, 검증 데이터 분할 (split abalone dataset into training and test set)


이번 예제에서는 MADlib을 사용하여 간단하게 성(sex)별로 shucked_weight와 diameter 설명변수를 사용하여 rings 를 예측하는 다중 선형회귀모형을 적합하고, 예측하는 것입니다. 


이를 위해 먼저 training set : test set = 0.8 : 0.2 의 비율로 데이터셋을 분할하겠습니다. madlib.train_test_split() 함수를 사용하며, 아래처럼 SQL의 select 문 안에 순서대로 인자를 써주면 됩니다. 이때 '성(sex)' 별을 기준으로 층화임의추출(stratified random sampling)을 해주었으며, 비복원 추출 (sample with replacement = FALSE 로 설정) 을 하려고 합니다. Output table 이름에 'out'이라고 해주었으며, Separate output tables = TRUE 로 설정하여 train과 test 테이블을 별도로 구분해서 만들어주라고 함에 따라 'out_train', 'out_test' 라는 이름으로 자동으로 naming 되어 두개의 테이블이 생성이 됩니다. 


out_train, out_test 의 각 테이블별로 성별(sex)로 관측치 개수를 세어보니 0.8 : 0.2 의 비율로 성(sex) 별 층화추출이 잘 되었네요. 



-- Train, Test set split

DROP TABLE IF EXISTS out_train, out_test;

SELECT madlib.train_test_split(

'abalone',  -- Source table

'out',      -- Output table

        0.8,        -- train_proportion

        NULL,       -- Default = 1 - train_proportion = 0.5

        'sex',      -- Strata definition

        'rings, shucked_weight, diameter', -- Columns to output

        FALSE,      -- Sample with replacement

        TRUE);      -- Separate output tables



-- Check

SELECT * FROM out_train LIMIT 5;




SELECT sex, count(*) FROM out_train GROUP BY sex;




SELECT sex, count(*) FROM out_test GROUP BY sex;






  4. 성별 그룹별 선형회귀모형 적합 

     (training linear regression models by 'sex' groups')


위의 3번에서 분할(split)한 훈련 데이터셋(training set)인 'out_train' 테이블을 대상으로   의 다중 선형회귀모형을 madlib.linregr_train() 함수를 사용하여 성별('sex') 그룹별로 나누어서 적합(fit)시켜 보겠습니다. 

MADlib에는 그룹별로 모형을 각각 적합시킬 때 아래의 예처럼 GroupBy 칼럼 이름을 넣어주면 알고리즘 내부적으로 Group별로 (이 예제에서는 'sex' 별로) 분산병렬처리하여 복수의 모델을 적합시켜 줍니다! 수 테라바이트의 대용량 데이터라도 전수로 분산병렬처리해서 신속하게 모델을 적합시킬 수 있으니 대단히 아주 유용합니다. (로컬 싱글 머신에서 R이나 Python 사용할 때처럼 메모리 full 나서 다운되거나, 몇 시간씩 걸리는 일 없습니다)



-- Linear Regression using MADlib

-- Train a regression model. 

DROP TABLE IF EXISTS abalone_linregr, abalone_linregr_summary;

SELECT madlib.linregr_train(

    'out_train'         -- table containing training data

    , 'abalone_linregr' -- table in which to save results

    , 'rings'           -- column containing dependent variable

    , 'ARRAY[1, shucked_weight, diameter]' -- features included in the model

    , 'sex'); -- create multiple output models (one for each value of sex)



* MADlib linear regression: https://madlib.apache.org/docs/latest/group__grp__linreg.html




  5. 성별 그룹별 선형회귀모형 회귀계수 조회 

     (select coefficients per variables by 'sex' groups)


위의 4번에서 성별('sex') 그룹별로 각각 분산병렬처리해서 훈련한 선형회귀모형의 적합 결과를 조회해보겠습니다. select 문의 from 절에 위의 4번에서 설정한 output table 이름인 "abalone_linregr" 테이블을 써주면 됩니다. 


그런데 다중 선형회귀모형이다보니 Y절편 intercept 와 'shucked_weight', 'diameter' 의 두개의 설명변수가 사용되어 성별로 각각 적합된 모델의 회귀계수(regression coefficients), 결정계수(), 표준오차(standard error), T 통계량(t-statistics), P 값 (P-values) 의 칼럼에 'intercept', 'shucked_weight', 'diameter' 의 순서대로 3개 값들이 콤마로 구분되어 array 형태로 들어가 있기에 읽기에 좀 힘듭니다. 



-- Examine the resulting models

SELECT * FROM abalone_linregr ORDER BY sex;





사람이 눈으로 보기에 좀더 가독성이 있도록 unnest() 함수를 사용해서 array를 세로로 긴 형태로 풀어서 다시 한번 조회를 해보겠습니다. 아래에 예제 결과를 보는 것처럼 한결 보기에 좋습니다. 


-- unnest format

SELECT sex

, unnest(ARRAY['intercept', 'rings', 'diameter']) as attribute

, unnest(coef) as coefficient 

, unnest(std_err) as standard_error

, unnest(t_stats) as t_stat

, unnest(p_values) as pvalue

FROM abalone_linregr

ORDER BY sex;



위에 Apache MADlib으로 성별('sex')로 각각 적합한 선형회귀모형의 회귀계수는 이전 포스팅에서 Greenplum에서 PL/R로 성별로 분산병렬처리해서 적합한 선형회귀모형(https://rfriend.tistory.com/529)의 회귀계수와 정확하게 일치합니다. 




  6. 성별 그룹별 선형회귀모형을 이용하여 예측 (prediction by 'sex' groups)


위의 5번에서 training set을 이용해 성별로 각각 선형회귀모형을 적합하였으니, 이번에는 3번에서 분할하여 따로 떼어놓았던 test set을 대상으로 예측(prediction)하여 보고, 실제값과 예측값의 차이를 비교해서 모델의 성능을 평가해보겠습니다. 


예측에는 madlig.linregr_predict() 라는 함수를 이용하며, input은 array[] 형태로 데이터를 변화해주어야 합니다. 아래 예에서 ARRAY[1, shucked_weight, diameter] 에서 '1'은 intercept 항을 의미합니다. 


Greenplum DB에서 MADlib으로 훈련한 모델을 사용하여 MADlib으로 대용량 데이터어 대해 예측/스코어링을 하면 역시 분산병령처리가 되어 대단히 빠르게 결과값을 반환합니다!



-- compare predicted value with actual with grouping

DROP TABLE IF EXISTS abalone_pred;

CREATE TABLE abalone_pred AS (

SELECT a.sex, a.shucked_weight, a.diameter, a.rings, 

madlib.linregr_predict(m.coef

, ARRAY[1, shucked_weight, diameter]

) as predict_val

, rings - madlib.linregr_predict(m.coef

, ARRAY[1, shucked_weight, diameter]

) as residual

FROM out_test a, abalone_linregr m

WHERE a.sex = m.sex) DISTRIBUTED BY (sex);



SELECT * FROM abalone_pred WHERE sex = 'F' LIMIT 10;





위의 6번에서 만든 실제값과 예측값 테이블 'abalone_pred' 을 이용해서 다양한 통계량 지표로 선형회귀모형의 적합도 평가해보겠습니다. 이중에서 실제값과 예측값이 차이의 제곱을 평균한 Mean Squared Error를 성별('sex') 그룹별로 madlib.mean_squared_error() 함수를 사용하여 계산해보겠습니다. (함수의 위치에 각 인자값을 넣어주면 됩니다.)



-- Model Performance Evaluation: Mean Squared Error

DROP TABLE IF EXISTS abalone_mse;

SELECT madlib.mean_squared_error(

'abalone_pred'   -- table_in

, 'abalone_mse'  -- table_out

, 'predict_val'  -- prediction_col

, 'rings'        -- observed_col

, 'sex');        -- grouping_cols

SELECT * FROM abalone_mse;





위에서 소개한 MSE를 계산하는 방식으로 MAE (Mean Absolute Error), MAPE (Mean Absolute Percentage Error), MPE (Mean Percentage Error), R-squared, Adjusted R-squared 등을 계산할 수 있습니다. (아래의 함수별 인자 위치를 참고해서  select madlib.함수(인자1, 인자2, ... ) 이런식으로 써주면 됩니다. 위의 MSE 계산하는 예제 참고하세요). 



-- Mean absolute error

madlib.mean_abs_error(table_in, table_out, prediction_col, observed_col, grouping_cols)


-- Mean absolute percentage error

madlib.mean_abs_perc_error(table_in, table_out, prediction_col, observed_col, grouping_cols)


-- Mean percentage error

madlib.mean_perc_error(table_in, table_out, prediction_col, observed_col, grouping_cols)


-- Mean squared error

madlib.mean_squared_error(table_in, table_out, prediction_col, observed_col, grouping_cols)


-- R-squared

madlib.r2_score(table_in, table_out, prediction_col, observed_col, grouping_cols)


-- Adjusted R-squared

madlib.adjusted_r2_score(table_in, table_out, prediction_col, observed_col, num_predictors, training_size, grouping_cols)

 


* MADlib Model Selection - Prediction Metrics: https://madlib.apache.org/docs/latest/group__grp__pred.html


다음 포스팅에서는 PivotalR을 활용하여 Greenplum, PostgreSQL DB에서 그룹별 선형회귀모형 적합 및 예측(https://rfriend.tistory.com/534) 하는 방법을 소개하겠습니다. 


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)



728x90
반응형
Posted by Rfriend
,