R로 간트 차트 그리기

R을 사용해 간트(Gantt) 차트 그리기

간트 차트(Gantt chart)는 프로젝트 일정관리를 위한 바(bar)형태의 도구로서, 각 업무별로 일정의 시작과 끝을 그래픽으로 표시하여 전체 일정을 한눈에 볼 수 있다. -wiki

회사 생활을 하다보니 종종 간트 차트를 그리는 일이 있습니다. 많은 사람들이 엑셀을 가지고 그리는 경우가 많은데 조금 더 미려한 플랏을 그리는 방법이 없을까 찾아보니 파이썬보다는 R로 그리는 편이 수월한 것 같더군요. 아래에는 ganttrifyplan 이라는 도구를 사용하는 방법에 대한 예제 코드 입니다.

0. 사용한 R 환경 정보

In [1]:
R.Version()
$platform
'x86_64-conda-linux-gnu'
$arch
'x86_64'
$os
'linux-gnu'
$system
'x86_64, linux-gnu'
$status
''
$major
'4'
$minor
'1.1'
$year
'2021'
$month
'08'
$day
'10'
$`svn rev`
'80725'
$language
'R'
$version.string
'R version 4.1.1 (2021-08-10)'
$nickname
'Kick Things'

1. 필요한 도구 설치하기

R에서는 install.packages('ganttrify') 명령어로 간단하게 도구들을 설치할 수 있습니다. 설치가 완료되면 library("ganttrify") 명령어를 실행해 불러와야 합니다.

In [30]:
#install.packages('ganttrify')
library("ganttrify")

library(repr) # jupyter notebook에서 플랏의 크기를 조절하기 위한 도구

2. 간트 차트 그리기

먼저 플랏의 크기를 설정해야 합니다. 간트차트는 일반적으로 옆으로 넓은 형태임으로 repr도구를 사용해 크기를 설정하였습니다. ganttrify에 이미 포함되어 있는 test_project데이터를 사용해 그려볼 것입니다. 다음의 간단한 코드로 미려한 플랏이 그려집니다.

In [54]:
options(repr.plot.width=15, repr.plot.height=4) 
# jupyter notebook에서 플랏 크기 조절

ganttrify(project = ganttrify::test_project,
          project_start_date = "2021-03",
          font_family = "Roboto Condensed")
No description has been provided for this image

2.1. 특정 시점 표기하기

spot옵션을 사용하면 간트 차트에 시점을 표기할 수도 있습니다.

In [55]:
ganttrify(project = ganttrify::test_project,
          spots = ganttrify::test_spots,
          project_start_date = "2021-03",
          font_family = "Roboto Condensed")
No description has been provided for this image

2.2. 분기 표시하기

분기에 따른 선을 그어서 다음과 같이 그릴 수도 있습니다.

In [56]:
ganttrify(project = ganttrify::test_project,
          spots = ganttrify::test_spots,
          project_start_date = "2021-03",
          size_text_relative = 1.2, 
          mark_quarters = TRUE,
          font_family = "Roboto Condensed")
No description has been provided for this image

2.3. 대분류 감추기

각각의 업무를 포괄하는 대분류(WP)를 감춘 그림을 그릴 수도 있습니다. 다만 아쉬운 것은 대분류는 표기하지만 bar graph는 그리지 않는 기능은 아직 없는 것 같습니다.

In [57]:
ganttrify(project = ganttrify::test_project,
          hide_wp = TRUE,
          font_family = "Roboto Condensed")
No description has been provided for this image

2.4. 그래프 모양을 변경하기

bar graph을 끝을 각지게 하는 방법과 반투명하게 만드는 방법은 다음과 같습니다.

In [58]:
ganttrify(project = ganttrify::test_project,
          project_start_date = "2021-04",
          alpha_wp = 0.9,
          alpha_activity = 0.6,
          line_end = "butt")
No description has been provided for this image

2.5. 문자 왼쪽 정렬하기

기본적으로 업무들은 오른쪽 정렬로 그려집니다. 만약 왼쪽으로 정렬되기를 원하면 다음과 같이 작성하면 됩니다.

In [60]:
ganttrify(project = ganttrify::test_project,
          spots = ganttrify::test_spots,
          project_start_date = "2021-04",
          axis_text_align = "left")
No description has been provided for this image

2.6. 플랏에 글씨 추가하기

다음과 같이 플랏의 제목과 출처등을 표기할 수도 있습니다.

In [63]:
options(repr.plot.width=15, repr.plot.height=7) 
# jupyter notebook에서 fig size 조절

ganttrify(project = ganttrify::test_project,
          spots = ganttrify::test_spots,
          project_start_date = "2020-01",
          font_family = "Roboto Condensed")+ ggplot2::labs(title = "My beautiful plans for 2020",
                subtitle = "I will definitely comply with the exact timing of each and all activities*",
                caption = "* I mean, I'll do my best, but if there's a pandemic or something, it's not my fault really")
No description has been provided for this image

3. 다른 도구 사용하기

plan 이라는 도구를 사용해서 그려봅니다. 참고로 plan은 이미 오래전에 개발이 중단된 것 같습니다. 현재 시점에는 ganttrify를 사용하는것이 더 좋을 것 같습니다. 그래도 plan의 사용법이 아주 간단해 간략하게 알아보겠습니다.

3.1. 공식 예제 코드

다음은 plan의 개발자가 제공하는 공식 예제 코드입니다.

In [33]:
#install.packages('plan') # plan 도구 설치
library(plan) # plan 도구를 불러옵니다.

g <- new("gantt")
g <- ganttAddTask(g, "Courses") # no times, so a heading
g <- ganttAddTask(g, "Physical Oceanography (A)", "2016-09-03", "2016-12-05", done=100)
g <- ganttAddTask(g, "Chemistry Oceanography (B)", "2016-09-03", "2016-12-05", done=100)
g <- ganttAddTask(g, "Fluid Dynamics (A+)", "2016-09-03", "2016-12-05", done=100)
g <- ganttAddTask(g, "Biological Oceanography", "2017-01-03", "2017-04-05")
g <- ganttAddTask(g, "Geological Oceanography", "2017-01-03", "2017-04-05")
g <- ganttAddTask(g, "Time-series Analysis", "2017-01-03", "2017-04-05")
g <- ganttAddTask(g, "Research") # no times, so a heading
g <- ganttAddTask(g, "Literature review", "2016-09-03", "2017-02-01", done=20)
g <- ganttAddTask(g, "Develop analysis skills", "2016-09-03", "2017-08-01", done=30)
g <- ganttAddTask(g, "Thesis work", "2016-10-01", "2018-07-15", done=30)
g <- ganttAddTask(g, "Thesis proposal", "2017-05-01", "2017-06-01")
g <- ganttAddTask(g, "Writing (papers & thesis)", "2017-03-01", "2018-07-15")
g <- ganttAddTask(g, "Defend thesis", "2018-09-01", "2018-09-05")

options(repr.plot.width=15, repr.plot.height=8) 
# jupyter notebook에서 fig size 조절

plot(g, ylabel=list(font=ifelse(is.na(g[["start"]]), 2, 1)),
     event.time="2016-12-13", event.label="Report Date")
legend("topright", pch=22, pt.cex=2, pt.bg=gray(c(0.3, 0.9)),
       border="black", 
       legend=c("Completed", "Not Yet Done"), title="MSc plan", bg="white")
No description has been provided for this image

3.2. 실제로 적용하기

plan은 할일 목록을 다음과 같이 직접 입력할 수 있어서 편리하기도 하지만 동시에 불편하기도 합니다.

g <- new("gantt")
g <- ganttAddTask(g, "Cell line dev.")
g <- ganttAddTask(g, "Top3 RCB","2020-01-15","2020-07-18",done=100)
g <- ganttAddTask(g, "Cell line stability","2020-07-01","2020-10-01",done=100)
g <- ganttAddTask(g, "MCB mfg and characterization","2020-07-15","2021-12-20",done=90)
g <- ganttAddTask(g, "Process development")
g <- ganttAddTask(g, "USP","2020-07-01","2021-03-01",done=100)
g <- ganttAddTask(g, "DSP","2020-08-12","2021-02-26",done=100)
g <- ganttAddTask(g, "Manufacturing")
g <- ganttAddTask(g, "Non-GMP DS","2021-02-26","2021-07-28",done=100)
g <- ganttAddTask(g, "Non-GMP DP","2021-07-26","2021-08-28",done=100)
g <- ganttAddTask(g, "GMP DS","2021-07-30","2021-10-28",done=100)
g <- ganttAddTask(g, "GMP DP","2021-10-26","2022-01-28",done=100)
g <- ganttAddTask(g, "Virus clearance study","2021-04-02","2021-12-28",done=90)
g <- ganttAddTask(g, "CTD documentation","2021-07-21","2022-01-31",done=40)

위의 할일 목록을 가지고 플랏을 그려봅니다.

In [24]:
plot(g, time.format="%Y-%m", time.labels.by,
     ylabel=list(font=ifelse(is.na(g[["start"]]), 2, 1)),
     event.label='Report Date',event.time='2021-10-27',
     main="Gantt plot by R")
No description has been provided for this image

3.3. 이벤트 추가하기

만약 두가지 이상의 이벤트를 추가하고 싶다면 다음과 같이 작성합니다.

In [27]:
# Plot with two events
event.label <- c("Proposal", "AGU")
event.time <- c("2021-05-21", "2021-10-27")

plot(g, time.format="%Y-%m", time.labels.by,
     ylabel=list(font=ifelse(is.na(g[["start"]]), 2, 1)),
     event.label=event.label,event.time=event.time,
     main="Gantt plot by R")
No description has been provided for this image

3.4. 세부 설정 변경하기

아래 코드와 같이 흑백이 아닌 색상으로도 변경이 가능하고 생각보다 다양한 것을 조절할 수 있습니다.

In [12]:
legend("topright", pch=22, pt.cex=2, cex=0.9, pt.bg=gray(c(0.3, 0.9)),
       border="black",
       legend=c("Completed", "Not Yet Done"), bg="white", xpd=TRUE)
 

plot(g, time.format="%Y-%m",
     event.label='Report Date',event.time='2021-10-27',
     col.event=c("red"),
     col.done=c("lightblue"),
     col.notdone=c("pink"),
     main="Gantt plot by R")

legend("topright", pch=22, pt.cex=2, cex=0.9, pt.bg=c("lightblue", "pink"),
       border="black",
       legend=c("Completed", "Not Yet Done"), bg="white", xpd=TRUE)
 
plot(g, xlim, time.format = "%Y-%m", time.labels.by="8 weeks",
    time.lines.by="8 weeks", event.time = NULL, event.label = NULL, event.side = 3,
    col.connector = "black", col.done = gray(0.3), col.notdone = gray(0.9),
    col.eventLine = gray(0.1), col.event = par("fg"),
    cex.event = par("cex"), font.event = par("font"),
    lty.eventLine = par("lty"), lwd.eventLine = par("lwd"), bg = par("bg"),
    grid.col = "lightgray", grid.lty = "dotted", ylabels = list(col=1, cex=1, font = 1, justification = 1),
    arrows = NULL, main = "",
    line.main = NA, cex.main = par("cex"), mgp = c(2, 0.7, 0), maiAdd = rep(0, 4), axes = TRUE, debug = FALSE)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

4. 마치며,

어떻게 생각하면 엑셀로 간단하게 할 수 있는 것을 번거롭게 하는 것일 수도 있겠습니다. 그래도 항상 같은 방법을 사용하는 것보다는 재미있으니까 예제 코드를 정리해 보았습니다.

돌연변이 위치에 따른 항체 생산량 예측하기

0. 목적

mljar-supervised라는 AutoML 패키지를 사용해 돌연변이 위치에 따른 항체 발현량 예측하는 문제를 풀어보겠습니다.

0.1. 데이터 출처

Ohri R, Bhakta S, Fourie-O'Donohue A, et al. High-Throughput Cysteine Scanning To Identify Stable Antibody Conjugation Sites for Maleimide- and Disulfide-Based Linkers. Bioconjug Chem. 2018;29(2):473-485. doi:10.1021/acs.bioconjchem.7b00791

0.2. 데이터셋 설명

데이터셋은 다음 9개의 열로 구성되어 있습니다.

  • Linker: maleimide linker(vc) 또는 pyridyl disulfide linker(PDS) 링커 구분
  • HC/LC: 항체의 light chain(LC) 혹은 heavy chain(HC) 표기
  • Residue: 원래의 아미노산 잔기
  • MutationSite: 돌연변이 부위
  • Conc(mg/ml): 단백질 농도는 280nm에서 흡광도와 280nm에서 항체의 흡광 계수를 사용하여 계산되었습니다.
  • %Agg: 응집된 항체의 비율은 SE-HPLC에 의해 평가되었습니다.
  • DAR: 약물 대 항체 비율, mAb에 접합 된 약물의 수는 LC/MS 분석에 의해 정량화되었습니다.
  • Reox: LC/MS 분석을 통해 항체가 정상적으로 reoxidation되었는지 판단합니다.
  • Stability: 랫(Rat)의 혈장에서 37도로 48시간 두었을때 변화한 DAR 비율

1. mljar-supervised

mljar-supervised는 테이블 형식 데이터에 작동하는 자동화된 기계 학습 파이썬 패키지입니다. 데이터를 전처리하고, 기계 학습 모델을 구성하고, 하이퍼 매개 변수 조정을 수행하여 최상의 모델을 찾는 일반적인 방법을 추상화 해서 우리의 시간을 절약하도록 설계되었습니다😎.

1.1. 설치

다음과 같이 pip 명령어를 사용해 설치할 수 있습니다.

pip install mljar-supervised

더 자세한 설치방법은 다음의 링크 https://github.com/mljar/mljar-supervised 를 확인하세요.

2. 분석하기

먼저 pandas를 사용해 해당 데이터셋의 내용을 살펴봅니다.

In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.read_csv("adc.csv")
df.head(10)
Out[1]:
Linker HC/LC Residue MutationSite Conc.(mg/mL) %Agg DAR Reox Avg.Stability
0 PDS HC E 1 3.7 43 1.0 Y 3
1 PDS HC V 2 3.1 13 1.6 Y 36
2 PDS HC Q 3 2.4 9 1.5 Y 48
3 PDS HC L 4 2.2 26 1.4 Y 8
4 PDS HC V 5 3.1 12 1.6 Y 84
5 PDS HC E 6 2.7 11 0.3 Y 19
6 PDS HC S 7 2.7 25 0.8 Y 12
7 PDS HC G 8 2.1 30 1.7 Y 1
8 PDS HC G 9 3.4 35 1.5 Y 2
9 PDS HC G 10 2.2 9 1.5 Y 1

데이터셋의 컬럼 목록, 모양, 간단한 수치 통계도 살펴봅니다.

In [2]:
df.columns
Out[2]:
Index(['Linker', 'HC/LC', 'Residue', 'MutationSite', 'Conc.(mg/mL)', '%Agg',
       'DAR', 'Reox', 'Avg.Stability'],
      dtype='object')
In [3]:
df.shape
Out[3]:
(1325, 9)
In [4]:
df.describe()
Out[4]:
MutationSite Conc.(mg/mL) %Agg DAR Avg.Stability
count 1325.000000 1325.000000 1325.000000 1325.000000 1325.00000
mean 187.340377 1.910189 24.507925 0.815019 40.01434
std 125.469780 0.909779 28.507051 0.705048 35.43867
min 1.000000 0.000000 0.000000 0.000000 0.00000
25% 83.000000 1.600000 7.000000 0.000000 3.00000
50% 166.000000 1.900000 13.000000 0.800000 37.00000
75% 284.000000 2.400000 27.000000 1.500000 67.00000
max 450.000000 5.100000 100.000000 2.000000 150.00000

seaborn을 사용해서 간단한 시각화도 해봅니다.

In [5]:
g = sns.PairGrid(df, diag_sharey=False)
g.map_upper(sns.scatterplot, s=15)
g.map_lower(sns.kdeplot)
g.map_diag(sns.kdeplot, lw=2)
Out[5]:
<seaborn.axisgrid.PairGrid at 0x7ffa3cf29880>
No description has been provided for this image

데이터들이 대체로 두가지 분류로 나뉘는 것을 알 수 있습니다. 예를 들면 농도가 0인 것과 2인 것으로 분류할 수 있고 %Agg 도 0에 가깝거나 100에 가까운 그룹으로 나눌 수 있겠습니다. 이런 데이터셋은 바이어스(bias)가 있을 가능성이 커서 기계 학습하기에는 적합하지 않다고 볼 수 있습니다.

3. mljar-supervised 사용하기

데이터셋을 학습용과 테스트용으로 나눕니다. 그리고 각각의 크기를 출력합니다.

In [6]:
from sklearn.model_selection import train_test_split
from supervised.automl import AutoML  # mljar-supervised

X = df[
    [
        "Linker",
        "HC/LC",
        "Residue",
        "MutationSite",
        "%Agg",
        "DAR",
        "Reox",
        "Avg.Stability",
    ]
]
y = df["Conc.(mg/mL)"]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.20, random_state=42
)
print(X_train.shape, X_test.shape)
(1060, 8) (265, 8)

3.1 AutoML로 모델 학습

In [7]:
automl = AutoML(mode="Explain")
automl.fit(X_train, y_train)
AutoML directory: AutoML_1
The task is regression with evaluation metric rmse
AutoML will use algorithms: ['Baseline', 'Linear', 'Decision Tree', 'Random Forest', 'Xgboost', 'Neural Network']
AutoML will ensemble availabe models
AutoML steps: ['simple_algorithms', 'default_algorithms', 'ensemble']
* Step simple_algorithms will try to check up to 3 models
1_Baseline rmse 0.933119 trained in 0.12 seconds
2_DecisionTree rmse 0.604529 trained in 8.69 seconds
3_Linear rmse 0.640778 trained in 2.3 seconds
* Step default_algorithms will try to check up to 3 models
4_Default_RandomForest rmse 0.584858 trained in 5.53 seconds
5_Default_Xgboost rmse 0.582731 trained in 2.88 seconds
6_Default_NeuralNetwork rmse 0.64666 trained in 5.2 seconds
* Step ensemble will try to check up to 1 model
Ensemble rmse 0.579981 trained in 0.12 seconds
AutoML fit time: 27.45 seconds
Out[7]:
AutoML()

학습된 모델의 성능은 rmse으로 측정되었으며 가장 좋은 값은 0.579981 입니다. mljar-supervised은 결과를 AutoML_XX라는 폴더로 저장해줍니다. 폴더 안을 각각의 모델에 대한 분석값이 들어 있습니다.

3.2. 예측 결과 시각화 하기

x축은 실제 값으로 y축은 예측된 값인 scatter plot을 그려봅니다.

In [8]:
predict_1 = automl.predict_all(X_test)

df_plot = pd.DataFrame()
df_plot["True_value"] = y_test.values
df_plot["Pred_1"] = predict_1.prediction.values

g = sns.jointplot(
    x="True_value", y="Pred_1", data=df_plot, kind="reg", truncate=False, height=7
)
No description has been provided for this image

3.3. hyper parameter 최적화하기

mljar-supervised에는 hyper parameter를 다음과 같이 손쉽게 최적화 할 수 있습니다.

In [9]:
automl = AutoML(algorithms=["Random Forest", "Xgboost"], mode="Compete")
automl.fit(X_train, y_train)
AutoML directory: AutoML_2
The task is regression with evaluation metric rmse
AutoML will use algorithms: ['Random Forest', 'Xgboost']
AutoML will stack models
AutoML will ensemble availabe models
AutoML steps: ['simple_algorithms', 'default_algorithms', 'not_so_random', 'golden_features', 'insert_random_feature', 'features_selection', 'hill_climbing_1', 'hill_climbing_2', 'ensemble', 'stack', 'ensemble_stacked']
Skip simple_algorithms because no parameters were generated.
* Step default_algorithms will try to check up to 2 models
1_Default_RandomForest rmse 0.596139 trained in 7.92 seconds
2_Default_Xgboost rmse 0.584039 trained in 1.59 seconds
* Step not_so_random will try to check up to 18 models
3_Xgboost rmse 0.599567 trained in 4.96 seconds
4_Xgboost rmse 0.593866 trained in 2.01 seconds
5_Xgboost rmse 0.593954 trained in 1.53 seconds
6_Xgboost rmse 0.596786 trained in 2.01 seconds
7_Xgboost rmse 0.589096 trained in 1.93 seconds
8_Xgboost rmse 0.603613 trained in 1.65 seconds
9_Xgboost rmse 0.607813 trained in 1.82 seconds
10_Xgboost rmse 0.596479 trained in 2.32 seconds
11_Xgboost rmse 0.598566 trained in 3.15 seconds
12_RandomForest rmse 0.595774 trained in 6.92 seconds
13_RandomForest rmse 0.601367 trained in 8.41 seconds
14_RandomForest rmse 0.593025 trained in 9.41 seconds
15_RandomForest rmse 0.596608 trained in 9.5 seconds
16_RandomForest rmse 0.591571 trained in 7.94 seconds
17_RandomForest rmse 0.594513 trained in 8.38 seconds
18_RandomForest rmse 0.594856 trained in 6.64 seconds
19_RandomForest rmse 0.596395 trained in 7.75 seconds
20_RandomForest rmse 0.5851 trained in 8.1 seconds
* Step golden_features will try to check up to 1 model
Add Golden Feature: %Agg_diff_DAR
Add Golden Feature: %Agg_diff_Avg.Stability
Add Golden Feature: Avg.Stability_ratio_MutationSite
Add Golden Feature: MutationSite_ratio_Avg.Stability
Add Golden Feature: DAR_diff_Avg.Stability
Created 5 Golden Features in 0.16 seconds.
2_Default_Xgboost_GoldenFeatures rmse 0.583598 trained in 2.04 seconds
* Step insert_random_feature will try to check up to 1 model
2_Default_Xgboost_GoldenFeatures_RandomFeature rmse 0.587742 trained in 3.47 seconds
Drop features ['DAR_diff_Avg.Stability', 'MutationSite_ratio_Avg.Stability', 'Avg.Stability_ratio_MutationSite', 'random_feature', 'Residue_T', 'Residue_L', 'Residue_F', 'Residue_N', 'Residue_Y', 'Linker', 'Residue_P', 'Residue_R', 'Reox', 'Residue_K', 'Residue_Q', 'Residue_I', 'Residue_H', 'Residue_C', 'Residue_D', 'Residue_G', 'Residue_W', 'Residue_A', 'Residue_M', 'Residue_S', 'Residue_E']
* Step features_selection will try to check up to 2 models
20_RandomForest_SelectedFeatures rmse 0.584829 trained in 8.33 seconds
2_Default_Xgboost_GoldenFeatures_SelectedFeatures rmse 0.577184 trained in 1.58 seconds
* Step hill_climbing_1 will try to check up to 7 models
21_RandomForest_SelectedFeatures rmse 0.585223 trained in 7.64 seconds
22_RandomForest rmse 0.591711 trained in 7.91 seconds
23_RandomForest rmse 0.593245 trained in 9.45 seconds
24_RandomForest rmse 0.590171 trained in 6.85 seconds
25_Xgboost_GoldenFeatures_SelectedFeatures rmse 0.574951 trained in 1.61 seconds
26_Xgboost_GoldenFeatures rmse 0.584706 trained in 1.81 seconds
27_Xgboost rmse 0.579199 trained in 1.72 seconds
* Step hill_climbing_2 will try to check up to 4 models
28_RandomForest_SelectedFeatures rmse 0.586703 trained in 5.99 seconds
29_Xgboost_GoldenFeatures_SelectedFeatures rmse 0.575996 trained in 1.61 seconds
30_Xgboost_GoldenFeatures_SelectedFeatures rmse 0.579304 trained in 1.57 seconds
31_Xgboost rmse 0.581736 trained in 1.63 seconds
* Step ensemble will try to check up to 1 model
Ensemble rmse 0.569821 trained in 3.57 seconds
* Step stack will try to check up to 10 models
25_Xgboost_GoldenFeatures_SelectedFeatures_Stacked rmse 0.580141 trained in 2.0 seconds
29_Xgboost_GoldenFeatures_SelectedFeatures_Stacked rmse 0.582319 trained in 2.21 seconds
2_Default_Xgboost_GoldenFeatures_SelectedFeatures_Stacked rmse 0.582473 trained in 2.06 seconds
27_Xgboost_Stacked rmse 0.582971 trained in 2.06 seconds
30_Xgboost_GoldenFeatures_SelectedFeatures_Stacked rmse 0.5845 trained in 1.84 seconds
31_Xgboost_Stacked rmse 0.581005 trained in 2.06 seconds
2_Default_Xgboost_GoldenFeatures_Stacked rmse 0.584416 trained in 2.16 seconds
2_Default_Xgboost_Stacked rmse 0.583641 trained in 2.09 seconds
26_Xgboost_GoldenFeatures_Stacked rmse 0.580362 trained in 2.2 seconds
2_Default_Xgboost_GoldenFeatures_RandomFeature_Stacked rmse 0.585285 trained in 4.73 seconds
* Step ensemble_stacked will try to check up to 1 model
Ensemble_Stacked rmse 0.569267 trained in 6.07 seconds
AutoML fit time: 210.63 seconds
Out[9]:
AutoML(algorithms=['Random Forest', 'Xgboost'], mode='Compete')

가장 좋은 rmse값은 0.569267 입니다. 큰 진전은 없어보입니다. 다시 시각화를 해서 살펴보겠습니다.

In [10]:
predict_2 = automl.predict_all(X_test)

df_plot["Pred_2"] = predict_2.prediction.values
g = sns.jointplot(
    x="True_value", y="Pred_2", data=df_plot, kind="reg", truncate=False, height=7
)
No description has been provided for this image

기존 모델과 최적화된 모델의 차이를 scatter plot 시각화해서 살펴보겠습니다.

In [14]:
plt.figure(figsize=(7, 7))
plt.plot(y_test, predict_1.prediction, ".", label="model1")
plt.plot(y_test, predict_2.prediction, ".", label="model2")
plt.ylim(-0.1, 4.5)
plt.xlim(-0.1, 4.5)
plt.xlabel("True value")
plt.ylabel("Predicted value")
plt.legend()
Out[14]:
<matplotlib.legend.Legend at 0x7ff97a4c3850>
No description has been provided for this image

큰 차이는 보이지 않지만 hyper parameter가 최적화된 모델에는 몇개의 데이터가 중심에서 벗어난 것 처럼 보입니다.

4. 마치며

그동안 기계 학습에서 적합한 모델을 선택하고 hyper parameter를 최적화하는 작업은 사용자가 할 일이라고 여겨져왔습니다. 그러나 AutoML이라는 개념이 등장하면서 이제 사용자들은 feature engineering에 집중할 수 있게 되었습니다. 그런 AutoML 도구 중에 mljar-supervised 패키지는 쉬운 사용법과 상당히 깔끔한 보고서를 만들 수 있게 해줍니다. 앞으로는 feature engineering 마져 자동화하는 도구가 나올지도 모른다는 생각이 듭니다.