深度學期快速入門

Lesson 2 人工智慧基礎介紹

林嶔 (Lin, Chin)

第一節:基本知識(1)

\[\hat{y} = f(x)\]

\[\hat{y} = f(x) = b_{0} + b_{1}x\]

第一節:基本知識(2)

\[loss = diff(y, \hat{y})\] - 以簡單線性迴歸的損失函數為例,所求的值為殘差平方和,可將此式改寫為:

\[loss = diff(y, \hat{y}) = \sum \limits_{i=1}^{n} \left(y_{i} - \hat{y_{i}}\right)^{2}\]

\[loss = diff(y, f(x))\]

\[loss = diff(y, f(x)) = \sum \limits_{i=1}^{n} \left(y_{i} - \left(b_{0} + b_{1}x_{1,i}\right)\right)^{2}\]

第一節:基本知識(3)

\[min(loss)\]

第二節:決策樹(1)

F01

F02

第二節:決策樹(2)

– 需要特別注意的是,對於資料科學實驗的流程,我們通常會把樣本分為3個部分,分別是:

  1. 訓練組(Training set, Development set):負責用來建構一個預測模型,我們之前學的三大流程就是用在這上面的,樣本可以隨意調整

  2. 驗證組(Validation set, Tuning set):不參與模型訓練,但會用來指導模型訓練,以及建構重要的資訊所用,樣本可以隨意調整

  3. 測試組(Testing set, Hold-out set, Validation set):最終模型會在上面運行一次(只能一次),已確定最終的準確度,原則上樣本選取必須符合未來使用條件

– 實務上,訓練組跟驗證組在不選擇模型的前提下可以合併,但測試組是必須的。

iris <- read.csv('data/iris.csv')

#Split data

set.seed(1)

Train.sample <- sample(1:150, 100, replace = FALSE)

Train.data <- iris[Train.sample,]
Test.data <- iris[-Train.sample,]

第二節:決策樹(3)

library(party)

tree.model <- ctree(formula = Species ~ ., data = Train.data)
tree.model
## 
##   Conditional inference tree with 3 terminal nodes
## 
## Response:  Species 
## Inputs:  Sepal.Length, Sepal.Width, Petal.Length, Petal.Width 
## Number of observations:  100 
## 
## 1) Petal.Length <= 1.9; criterion = 1, statistic = 92.735
##   2)*  weights = 32 
## 1) Petal.Length > 1.9
##   3) Petal.Width <= 1.6; criterion = 1, statistic = 48.709
##     4)*  weights = 35 
##   3) Petal.Width > 1.6
##     5)*  weights = 33
pred.y <- predict(tree.model, Test.data[,1:4])
table(pred.y, Test.data[,5])
##             
## pred.y       setosa versicolor virginica
##   setosa         18          0         0
##   versicolor      0         14         3
##   virginica       0          0        15
plot(tree.model)

第二節:決策樹(4)

dat <- read.csv("data/ECG_train.csv", header = TRUE, fileEncoding = 'CP950', stringsAsFactors = FALSE, na.strings = "")
  1. AMI:這是個類別變項描述心肌梗塞的狀態,包含STEMI、NSTEMI及not-AMI

  2. K:這是一個連續變項描述鉀離子的濃度

  3. LVD:這是一個二元類別變項:1代表left ventricular dysfunction,0則代表正常

  4. time與death:這組變項描述病患隔多久後死亡與否,這用來做存活分析之用

– 除了性別(GENDER)和年齡(AGE)外,心電圖的重要參數包含了8個連續變項特徵(Rate、PR、QRSd、QT、QTc、Axes_P、Axes_QRS、Axes_T)以及31個二元類別變項描述相對應的rhythm。

– rhythm依序為:abnormal T wave、atrial fibrillation、atrial flutter、atrial premature complex、complete AV block、complete left bundle branch block、complete right bundle branch block、first degree AV block、incomplete left bundle branch block、incomplete right bundle branch block、ischemia/infarction、junctional rhythm、left anterior fascicular block、left atrial enlargement、left axis deviation、left posterior fascicular block、left ventricular hypertrophy、low QRS voltage、pacemaker rhythm、prolonged QT interval、right atrial enlargement、right ventricular hypertrophy、second degree AV block、sinus bradycardia、sinus pause、sinus rhythm、sinus tachycardia、supraventricular tachycardia、ventricular premature complex、ventricular tachycardia、Wolff-Parkinson-White syndrome

– 在大部分的狀態下,我們會使用後面的幾個變項去預測前面的4組變項。

第二節:決策樹(5)

– 這裡給一些範例語法,讓大家知道怎樣用在不同的依變項屬性上。

  1. 這是連續變項的範例:
subdat <- dat[!(dat[,'K'] %in% NA) & !(dat[,'Rate'] %in% NA) & !(dat[,'AGE'] %in% NA), c('K', 'Rate', 'AGE')]

tree.model <- ctree(formula = K ~ ., data = subdat)
plot(tree.model)

  1. 這是二元分類的範例:
subdat <- dat[!(dat[,'LVD'] %in% NA) & !(dat[,'GENDER'] %in% NA) & !(dat[,'Rate'] %in% NA), c('LVD', 'GENDER', 'Rate')]
subdat[,'GENDER'] <- as.factor(subdat[,'GENDER'])
subdat[,'LVD'] <- as.factor(subdat[,'LVD'])

tree.model <- ctree(formula = LVD ~ ., data = subdat)
plot(tree.model)

  1. 這是多分類任務的範例:
subdat <- dat[!(dat[,'AMI'] %in% NA) & !(dat[,'GENDER'] %in% NA) & !(dat[,'AGE'] %in% NA), c('AMI', 'GENDER', 'AGE')]
subdat[,'GENDER'] <- as.factor(subdat[,'GENDER'])
subdat[,'AMI'] <- as.factor(subdat[,'AMI'])

tree.model <- ctree(formula = AMI ~ ., data = subdat)
plot(tree.model)

第二節:決策樹(6)

  1. 參數【mincriterion】是顯著水準

  2. 參數【maxdepth】是樹的最大深度

  3. 參數【minsplit】是說樣本大於多少,才考慮繼續分類

  4. 參數【minbucket】是說每個分類至少要有幾個樣本

subdat <- dat[!(dat[,'LVD'] %in% NA) & !(dat[,'GENDER'] %in% NA) & !(dat[,'Rate'] %in% NA), c('LVD', 'GENDER', 'Rate')]
subdat[,'GENDER'] <- as.factor(subdat[,'GENDER'])
subdat[,'LVD'] <- as.factor(subdat[,'LVD'])

tree.model <- ctree(formula = LVD ~ ., data = subdat,
                    controls = ctree_control(mincriterion = 0.95, maxdepth = 2, minsplit = 20, minbucket = 7))
plot(tree.model)

– 如果你想獲得預測機率,可以用這種方式:

prob_list <- predict(tree.model, subdat, type = 'prob')
prob_y <- do.call('rbind', prob_list)[,1]

第三節:梯度提升機(1)

– 為什麼他這麼強呢?決策樹的缺點是模型都是建立在單一預測模的基礎上,容易因為樣本決定一個特定的極端條件。

F03

第三節:梯度提升機(2)

– 有趣的是,這樣模型的組合將可以讓我們擁有一個非線性模型。

  1. 先建立第一個模型:\(y = F_1(x) + \epsilon_1\)

  2. 根據第一個模型的殘差建立第二個模型:\(\epsilon_1 = F_2(x) + \epsilon_2\)

  3. 先將上面兩個式子合併,產生一個整合模型,並取得整合模型的殘差:\(y = F_1(x) + \eta F_2(x) + \tilde{\epsilon_2}\)

  4. 再根據這個殘差建立第三個模型:\(\tilde{\epsilon_2} = F_3(x) + \epsilon_3\)

  5. 再將三個式子合併,產生一個整合模型,並取得整合模型的殘差:\(y = F_1(x) + \eta F_2(x) + \eta F_3(x) + \tilde{\epsilon_3}\)

  6. 再根據這個殘差建立第四個模型:\(\tilde{\epsilon_3} = F_4(x) + \epsilon_4\)

  7. 再將三個式子合併,產生一個整合模型,並取得整合模型的殘差:\(y = F_1(x) + \eta F_2(x) + \eta F_3(x) + \eta F_4(x) + \tilde{\epsilon_4}\)

  8. 依此類推…

第三節:梯度提升機(3)

– 注意原始資料中存在「遺漏值」,一個比較簡單的方法是透過套件「mice」進行「多重插補法」

library(mice)

subdat <- dat[!(dat[,"LVD"] %in% NA), c(-1, -2, -4, -5)]

subdat[,'LVD'] <- as.factor(subdat[,'LVD'])
subdat[,'GENDER'] <- as.factor(subdat[,'GENDER'])
for (i in 1:31) {subdat[,paste0('rhythm.', i)] <- as.factor(subdat[,paste0('rhythm.', i)])}

used_dat.x <- subdat[,-1]
mice_dat <- mice(used_dat.x, m = 1, maxit = 5, meth = 'cart', seed = 123, printFlag = FALSE)
impute_dat.x <- mice:::complete(mice_dat, action = 1)

set.seed(0)
all_idx <- 1:nrow(subdat)

train_idx <- sample(all_idx, nrow(subdat) * 0.6)
valid_idx <- sample(all_idx[!all_idx %in% train_idx], nrow(subdat) * 0.2)
test_idx <- all_idx[!all_idx %in% c(train_idx, valid_idx)]

train_X <- impute_dat.x[train_idx,]
valid_X <- impute_dat.x[valid_idx,]
test_X <- impute_dat.x[test_idx,]

train_Y <- subdat[train_idx,"LVD"]
valid_Y <- subdat[valid_idx,"LVD"]
test_Y <- subdat[test_idx,"LVD"]

第三節:梯度提升機(4)

– 這個套件實現的是「eXtreme Gradient Boosting」,跟傳統的梯度提升機不完全一樣,但原理是類似的。

– 他必須吃矩陣格式的資料,並且還要轉換成自己的格式。

library(xgboost)

train_X_mat <- model.matrix(~ ., data = train_X)
xgb.data_train <- xgb.DMatrix(data = train_X_mat[,-1], label = as.integer(train_Y) - 1L)

valid_X_mat <- model.matrix(~ ., data = valid_X)
xgb.data_valid <- xgb.DMatrix(data = valid_X_mat[,-1], label = as.integer(valid_Y) - 1L)

xgb_fit <-  xgb.train(data = xgb.data_train, watchlist = list(eval = xgb.data_valid),
                      early_stopping_rounds = 10, eval_metric = 'auc', verbose = FALSE,
                      max.depth = 5, eta = 0.3,
                      nthread = 2, nrounds = 100, objective = "binary:logistic")
library(pROC)

pred_valid <- predict(xgb_fit, valid_X_mat[,-1])
roc_valid <- roc(valid_Y ~ pred_valid)
plot(roc_valid)
text(0.5, 0.5, paste0('AUC = ', formatC(roc_valid[['auc']], 4, format = 'f')), col = 'red')

第三節:梯度提升機(5)

– 按照我們先前的了解,【eta】應該越小就需要越多的【nrounds】,我們來試試看

xgb_fit <-  xgb.train(data = xgb.data_train, watchlist = list(eval = xgb.data_valid),
                      early_stopping_rounds = 10, eval_metric = 'auc', verbose = FALSE,
                      max.depth = 5, eta = 0.1,
                      nthread = 2, nrounds = 300, objective = "binary:logistic")
library(pROC)

pred_valid <- predict(xgb_fit, valid_X_mat[,-1])
roc_valid <- roc(valid_Y ~ pred_valid)
plot(roc_valid)
text(0.5, 0.5, paste0('AUC = ', formatC(roc_valid[['auc']], 4, format = 'f')), col = 'red')

第三節:梯度提升機(6)

test_X_mat <- model.matrix(~ ., data = test_X)
pred_test <- predict(xgb_fit, test_X_mat[,-1])
roc_test <- roc(test_Y ~ pred_test)

plot(roc_test)
text(0.5, 0.5, paste0('AUC = ', formatC(roc_test[['auc']], 4, format = 'f')), col = 'red')

importance_matrix <- xgb.importance(model = xgb_fit)
xgb.plot.importance(importance_matrix = importance_matrix)

第四節:人工神經網路(1)