The Practical Guide to the Random Forests - Random Forests Model Part I
(Using Kaggle’s Titanic Data with R code)

這篇Post是此系列的最後一篇, 我們終於能開始進入Random Forest這個強大的Ensemble技術領域。在所參考程式碼的Trevor Stephens文章中,尚有多出一篇討論Feature EngineeringpostRandom Forest模型介紹之前, 由於這系列Posts重點在於模型架構的闡釋, 所以, 雖然Feature EngineeringData Science分析流程中是一個重要的關鍵 - Feature Engineering的好壞對於模型績效有顯著的影響(feature engineering has been described as “the most important factor” in determining the success or failure of the predictive model), 我還是決定將Feature Engineering這一塊用重點條列的型式先行帶過。各位若有興趣, 可以自行參考Trevor Stephensoriginal post (http://trevorstephens.com/post/73461351896/titanic-getting-started-with-r-part-4-feature)
Feature Engineering這個Topic, 將另行撰寫Posts討論。



Feature Engineering

由於Trevor Stephens原文中Feature Engineering的結果數據,將會被應用於後續的Random Forest模型中, 我仍會將Trevor Stephens完整feature engineeringSample code附帶於文章中,並挑選程式碼中相對重要的部份, 進行解說。

首先, 建立一個新的資料集-combi,將訓練(train)以及預測(test)的資料集合併,這樣做的好處是可以將所有的數據參數進行一致性的feature engineering。我們使用rbind(which stands for row bind)這個function進行資料集合併
test$Survived <- NA
combi <- rbind(train, test)
第二步, 建立3feature engineering 欄位變數 – Title, FamilySize Surname
combi$Title <- sapply(combi$Name, FUN=function(x) {strsplit(x, split='[,.]')[[1]][2]}) 
…(中間省略)…
table(combi$Title)
combi$FamilySize <<- combi$SibSp + combi$Parch + 1
combi$Surname <- sapply(combi$Name, FUN=function(x) {strsplit(x, split='[,.]')[[1]][1]})

FamilySize Surname 兩個變數是為了產生FamilyID這個新欄位變數; Trevor Stephens想利用SurnameFamilySize兩個欄位,將不同Name的人組成一個Family. 他假定只要SurnameFamilySize都是相同的,應該是同一個Family, 所以給定一個FamilyID 數值.
combi$FamilyID <- paste(as.character(combi$FamilySize), combi$Surname, sep="")

Trevor Stephens設定了一個假設, FamilySize的大小會影響存活率, 因此他檢視了一些資料特性, 並將相關同樣邏輯特性的資料,FamilyID一律指定成Small
combi$FamilyID[combi$FamilySize <= 2] <- 'Small'
…(中間省略)…
combi$FamilyID[combi$FamilyID %in% famIDs$Var1] <- 'Small'
完成上述處理之後, 我們將切割資料數據回到原本的traintest兩個資料集;完整的程式碼post於下方。
train <- read.csv("D:/IDE/R/Titan/train.csv")
test <- read.csv("D:/IDE/R/Titan/test.csv")
test$Survived <- NA
combi <- rbind(train, test)
combi$Name <- as.character(combi$Name)
combi$Title <- sapply(combi$Name, FUN=function(x) {strsplit(x, split='[,.]')[[1]][2]})
combi$Title <- sub(' ', '', combi$Title)
combi$Title[combi$Title %in% c('Mme', 'Mlle')] <- 'Mlle'
combi$Title[combi$Title %in% c('Capt', 'Don', 'Major', 'Sir')] <- 'Sir'
combi$Title[combi$Title %in% c('Dona', 'Lady', 'the Countess', 'Jonkheer')] <- 'Lady'
combi$Title <- factor(combi$Title)
combi$FamilySize <- combi$SibSp + combi$Parch + 1
combi$Surname <- sapply(combi$Name, FUN=function(x) {strsplit(x, split='[,.]')[[1]][1]})
combi$FamilyID <- paste(as.character(combi$FamilySize), combi$Surname, sep="")
combi[combi$Surname=='Johnson',c('Surname','FamilySize','FamilyID','Name')]
combi[combi$Surname=='Appleton',c('Surname','FamilySize','FamilyID','Name')]
combi$FamilyID[combi$FamilySize <= 2] <- 'Small'
table(combi$FamilyID)
famIDs <- data.frame(table(combi$FamilyID))
famIDs <- famIDs[famIDs$Freq <= 2,]
combi$FamilyID[combi$FamilyID %in% famIDs$Var1] <- 'Small'
combi$FamilyID <- factor(combi$FamilyID)
train <- combi[1:891,]
test <- combi[892:1309,]

將資料集合併處理最關鍵的一點是建立R的完整參數factor數據。以FamilyID, train資料集中, 存在3FamilyID =‘3Johnson’的數據, 但是test資料集中完全沒有此項數據。若將兩個資料集分開處理建立FamilyID, test資料集的FamilyID參數的factor將不會有‘3Johnson’這個數值。這樣的狀況會造成在進行數據預測時, R系統會丟出錯誤(throw errors), 因為machine learning的訓練模型和預測的數據其factors不一致。

我們使用新建立的數據來建立CART model:
library(rpart)

fit <- rpart(Survived ~ Pclass + Sex + Age + SibSp + Parch + Fare + Embarked + Title + FamilySize + FamilyID,
             data=train, method="class")

library(rattle)
library(rpart.plot)
library(RColorBrewer)

fancyRpartPlot(fit)



從上圖可以發現,新建立的變數基本上主宰(govern)了整個決策樹的分析 TitleFamilyID兩個欄位分別居於第一和第二個Node位置。從上圖中亦可以發現在上一篇Post, 所提到Tree Modelselection bias現象: CART模型偏好選擇那些” factors with many levels 的欄位變數。其中Title變數有11 levelsfactor, FamliyID高達61 levels


Bootstrap Aggregation and Bagged Trees

Tree-based模型是一個high variance的演算法;Titanic data set為例子, 如果我們隨機將將訓練數據(train data set)切分成兩部份, 然後分別訓練建構兩個CART模型, 此兩個CART模型所預測的test data set結果會相當不一樣。這類因為不同的訓練數據(training data set)所造成模型預測結果的差異, 稱之為”variance”. Decision treeshigh variance模型, 相對的, 若模型的預測結果, 不會因為不同的訓練數據而大幅度地變化, 則為low variance模型; 線性迴歸(Regression Model)即為一種low variance模型。

Bootstrap aggregation, 或簡稱 Bagging,是一種降低vairance的統計學習演算法, 此演算法雖能運用在所有的Machine Learning模型, 但一般是與Tree-based模型結合使用。Bootstrap是一種Resampling技術。一般Resampling技術是用來建立更多的樣本(samples) for模型的建構與測試, 在之後另外一篇文章, 將會介紹其他Resampling技術, 以及如何使用Resampling技術, 進行模型的建立與調效(tuning).

我們可以圖示化Bootstrap技術如下:
Bootstrap Sample是從資料集中隨機抽取的樣本資料集, 此抽樣方法的特點整理如下:
ü 隨機抽取的樣本資料with replacement, 也就是抽取出來的資料會再放回資料集, 供下一次的隨機抽取
ü   樣本的數據大小(sample size)與原始資料集是一樣的
ü   有些樣本資料會被選取很多次; 相對地, 有些數據則完全不會被選到
ü   那些沒有被選到的樣本資料集, 我們稱之為”out-of-bag” samples. 從上圖可以看出, 每一次的Bootstrap Resampling, 演算法會依據所選取出來的samples建立模型, 然後用”out-of-bag” samples進行模型預測(predict)
ü   平均來說, 原始資料中, 63.2%的數據至少會被選取到一次。如果訓練資料集數據太小, Bootstrap技術將會產生high bias的問題; 此問題將可以隨著訓練數據的增加而降低。

大約在90年代中期, Ensemble techniques, 這種合併多項預測模型的技術開始出現。Bootstrap aggregation(簡稱Bagging)為這項技術的濫觴之一; BaggingLeo Breiman所提出, 是最早開發出來的Ensemble techniques (Breiman 1996a)Bagging是一個通用演算法, 其使用bootstrap技術將各式各樣的regression (classification)模型結合, 然後建構出一個Ensemble模型; Bagging的演算法概念如下方Algorithm 1(a)所描述。在ensemble中的每一個模型, 依照問題型態的不同, 分別使用兩種方式進行預測:
ü   For regression: m個預測數值平均

ü   For classification: 使用投票(votes)的比率決定預測類別



Bagging模型擁有3項優勢:
1.      首先, Bagging 可以非常有效率地透過 aggregation process”, 降低預測結果的變異性(the variance of a prediction)。因此對於Decision Trees這類會產生不穩定預測數據的模型, 彙聚多種版本訓練資料建立的模型所產生的預測結果, 能夠確實地降低預測的變化波動, 產生更為穩定的預測數值。
2.      由於Bagging的預測數值為平均多個獨立Decision Trees模型的預測數據,此方法不僅擁有low variance的預測結果, 相對地也增進了模型的預測績效(predictive performance)

3.      3Bagging優勢為, 此模型提供了內部估算預測績效”(internal estimate of predictive performance)。此預測績效數據可以讓我們推測 cross-validation estimates或是test set預估績效。[內部估算預測績效]的來源是上文提過的”out-of-bag” samples. Out-of-bag樣本是在該次bootstrap訓練模型時, 沒有被取樣的數據, 因此針對Out-of-bag樣本,就可以計算出該次模型對於未知資料的預測績效值, 我們稱此數值為”out-of-bag estimate”; 彙整並平均每次bootstrap的模型的預測績效, 我們就能量測出整個ensemble模型的預測能力。這是因為通常, out-of-bag estimate cross-validation estimatestest set estimates具有一定的相關聯性。

除了上述優點, Bagging模型同樣具有下列2項缺點:
1.          隨著bootstrap樣本數量增加, 電腦運算成本與記憶體需求也同步地向上增加。然而, 此系統效能問題可以藉由平行運算(parallel computing)架構改善, 因為Bagging流程能很容易地進行平行處理。讓我們回想一下Bagging的架構: 每一個bootstrap樣本數據各自對應其模型訓練; 也就是說, 每一個model是完全獨立, 可以分開建構的; 我們所有做的是在最後一個流程階段, 將所有模型預測進行彙整即可。

2.          Bagged model另外一個劣勢, 在於其模型的解釋程度下降(less interpretable) 然而我們依然可以透過合併多個單一模型的變數評測數據, 建立數據的變數重要性數值(measures of variable importance)

Random Forests模型 Part I 先在此做一個結束; 下一個Part將會解說Random Forests Model, 並運用此演算法Titanic 資料集進行分類預測


by J.D.