はじめに
機械学習に関して、Kaggleを中心に色々と腕試しをしているのですが、みんなどんなフォルダ/ファイル構成でやっているのかな?どれが効率的なのかな?と疑問に思ったので、まずは自分をさらけ出すことでフィードバックを貰おうというモチベーションでこの記事を書きました。
全体のフォルダ/ファイル構成
自分はairBnBのkaggleコンテストで2位を取られたkeikuさんのスクリプトをベースに今はこんな形で落ち着いています。
. /┬inputs/┬file1.csv
│ ├file2.csv
│ ├︙
├scripts/┬Run.R
│ ├Util.R
│ ├FeatureEngineering.R
│ ├Modeling.R
│ └Submission.R
├pattern1/┬output_pattern1.csv
│ └memo.txt
├pattern2/output_pattern2.csv
│ └memo.txt
︙
それぞれの用途としては下記の表の通りです
フォルダ名 | 用途 |
---|---|
inputs | ソースデータ置き場 |
scripts | スクリプト置き場 |
pattern(n) | 機械学習モデルによる予測ファイル置き場 |
inputsフォルダは基本的に一度ソースデータを置いたら何もいじることはなく、基本的にはscriptsフォルダ内にあるスクリプトをいじり倒す形になります。色々と設定を変えたり違う学習モデルを試したりした分だけ、patternフォルダが増えていくイメージです。
inputsフォルダは上記の通りで何も書くことはないので、主にscriptsフォルダについて書いていきます。
scriptsフォルダ
scripsフォルダ配下には5つのスクリプトファイルが置かれています。Run.Rがメインのスクリプトで、ここからUtil.R等のスクリプトを呼び出すような形になっています。
ファイル名 | 用途 |
---|---|
Run.R | 他のスクリプトを呼び出す |
Util.R | パッケージやソースデータの読込 |
FeatureEngineering.R | 特徴量エンジニアリング等前処理用 |
Modeling.R | 機械学習モデルを作成 |
Submission.R | 予測ファイルの生成、Validation等 |
Run.R
# *******************************************************
# name pattern ------------------------------------------
# *******************************************************
name <- "pattern_1"
# *******************************************************
# create folder------------------------------------------
# *******************************************************
dir.create("./pattern/")
dir.create(paste0("./pattern/", name))
dir.create(paste0("./pattern/", name, "/outputs"))
# *******************************************************
# run scripts -------------------------------------------
# *******************************************************
source("scripts/Util.R") # 設定ファイルやデータ読込
source("scripts/FeatureEngineering.R") # 前処理
source("scripts/Modeling.R") # 機械学習モデル作成
source("scripts/Submit.R") # 予測
Run.Rは非常にコンパクトなスクリプトで、それぞれ機械学習に必要な流れにそってスクリプトをキックするだけです(設定等読込->前処理->学習モデル作成->予測)。
一点ポイントとしては、このRun.Rを動かすたびに最初のnameオブジェクトに命名することです。これをすることで、アウトプット(予測ファイル)に何を試した結果のアウトプットなのかを名付けて、あとで見返すようにします1
Util.R
# *******************************************************
# load packages------------------------------------------
# *******************************************************
library(tidyverse) # default
library(data.table) # to use data.table class
library(lubridate) # for date & time data
library(RcppRoll) # to use window function
:
# *******************************************************
# load data ---------------------------------------------
# *******************************************************
assign_data <- function(path, type = "csv"){
names <- list.files(path = path,
full.names = F,
pattern = paste0("\\.", type, "$")) %>%
gsub(paste0(".",type), "",.)
paths <- list.files(path = path,
full.names = T,
pattern = paste0("\\.", type, "$"))
map2(names, paths, ~assign(.x, data.table::fread(.y, data.table = T), envir = .GlobalEnv))
}
system.time(lapply(list.dirs(path = "./inputs", recursive = T), assign_data))
Util.Rでは 主にパッケージやソースデータの読込みを行う。大体どの機械学習でも使うパッケージは同じだったりするので、使い回しが容易になります。データの読込みに関しては、以前書いたRで大量のデータファイルをまとめて読み込む方法の通り、自作で関数を作って、一括で読み込む様にしています。その他にも定数を管理を管理したりすることもあります。
さいごに
Run.RやUtil.Rは使い回しができるものとして中身まで紹介しましたが、それ以降は学習するデータによって大きく変わってくるので、本記事では割愛します。また、EDAの段階においてはR Notebookを使ってグラフとかを整理して管理したりもしているので、scriptsフォルダは実際はもっと雑多だったりもします。
人によってはEDAからモデル作成まで全部R Notebookの人も最近は多いと思うし、もしもっとこうした方がいいぜ的なノウハウをお持ちの人がいたらぜひ教えて欲しいです。
-
例えば"180302_Randomforest_mtree2"とか"180302_elastic_net_alpha0.5"とか ↩