1. 關聯式規則(Association Rules)
這裡拿網路上一個公開資料(鐵達尼號的乘客資料)來進行分析,資料載點如下。
下載之後,你會發現資料的型態並非熟悉的.csv。
因此我們要用函式把資料匯入到R裡面,使用的函式是load():
# 記得要給定資料所在的路徑(path),例如:我把下載的資料放在C槽下:
load("titanic.raw.rdata") #匯入.rdata檔(補充:如果我們要匯入.csv檔,除了之前教的方法以外,也可以用函式read.csv())
data <- read.csv("C:/data.csv")並且用str()看這筆資料的狀態
str(titanic.raw)## 'data.frame': 2201 obs. of 4 variables:
## $ Class : Factor w/ 4 levels "1st","2nd","3rd",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ Sex : Factor w/ 2 levels "Female","Male": 2 2 2 2 2 2 2 2 2 2 ...
## $ Age : Factor w/ 2 levels "Adult","Child": 2 2 2 2 2 2 2 2 2 2 ...
## $ Survived: Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
可以發現資料裡面有四個欄位:
Class:乘客的艙位等級
Sex:乘客性別
Age :乘客年齡
Survived:沉船之後,乘客是否存活?
關於鐵達尼號的故事,大家應該都耳熟能詳。而當我們說「女性比較容易存活」、以及「男性船員幾乎活不下來」,相信也沒人會反對吧?
畢竟電影就是這樣演的嘛!
可是,說歸說,如果要證明的話,該怎麼做呢?
啊啊啊!腦袋卡住了……
好啦,就不賣關子了。事實上這件事其實並不難。
其中一個方法,就是本篇即將用到的第一個方法:關聯式法則(apriori)!(對應的套件:arules)
apriori()建立關聯規則
require(arules) # apriori關聯式法則的套件還記得apriori演算法是怎麼運作的嗎?我們需要設定:
支持度(min support):「規則」在資料內具有普遍性,也就是這些 A 跟 B 同時出現的機率多少。
信賴度(min confidence):「規則」要有一定的信心水準,也就是當購買 A 狀態下,也會購買 B 的條件機率。
(以上忘記的話,趕緊去讀熟XD)
而我們想要探討的規則,形式如下:「在A情況下,會存活與否」
換句話說,可以寫成A => 存活與否,所以把Survived這個變數放在=>的右手邊(right hand side)
# apriori rules with rhs containing "Survived" only
rule <- apriori(titanic.raw,
# min support & confidence, 最小規則長度(lhs+rhs)
parameter=list(minlen=3, supp=0.1, conf=0.7),
appearance = list(default="lhs",
rhs=c("Survived=No", "Survived=Yes")
# 右手邊顯示的特徵
)
) 要觀察rule需要使用inspect()的函式:
inspect(rule)## lhs rhs support confidence
## [1] {Sex=Female,Age=Adult} => {Survived=Yes} 0.1435711 0.7435294
## [2] {Class=3rd,Sex=Male} => {Survived=No} 0.1917310 0.8274510
## [3] {Class=3rd,Age=Adult} => {Survived=No} 0.2162653 0.7591707
## [4] {Class=Crew,Sex=Male} => {Survived=No} 0.3044071 0.7772622
## [5] {Class=Crew,Age=Adult} => {Survived=No} 0.3057701 0.7604520
## [6] {Sex=Male,Age=Adult} => {Survived=No} 0.6038164 0.7972406
## [7] {Class=3rd,Sex=Male,Age=Adult} => {Survived=No} 0.1758292 0.8376623
## [8] {Class=Crew,Sex=Male,Age=Adult} => {Survived=No} 0.3044071 0.7772622
## lift count
## [1] 2.301699 316
## [2] 1.222295 422
## [3] 1.121433 476
## [4] 1.148157 670
## [5] 1.123325 673
## [6] 1.177669 1329
## [7] 1.237379 387
## [8] 1.148157 670
這時候,看你是想根據 support 大小,或是 lift 大小排序 rules :
# 以下舉 lift 為例
sort.rule <- sort(rule, by="lift")
inspect(sort.rule)## lhs rhs support confidence
## [1] {Sex=Female,Age=Adult} => {Survived=Yes} 0.1435711 0.7435294
## [2] {Class=3rd,Sex=Male,Age=Adult} => {Survived=No} 0.1758292 0.8376623
## [3] {Class=3rd,Sex=Male} => {Survived=No} 0.1917310 0.8274510
## [4] {Sex=Male,Age=Adult} => {Survived=No} 0.6038164 0.7972406
## [5] {Class=Crew,Sex=Male} => {Survived=No} 0.3044071 0.7772622
## [6] {Class=Crew,Sex=Male,Age=Adult} => {Survived=No} 0.3044071 0.7772622
## [7] {Class=Crew,Age=Adult} => {Survived=No} 0.3057701 0.7604520
## [8] {Class=3rd,Age=Adult} => {Survived=No} 0.2162653 0.7591707
## lift count
## [1] 2.301699 316
## [2] 1.237379 387
## [3] 1.222295 422
## [4] 1.177669 1329
## [5] 1.148157 670
## [6] 1.148157 670
## [7] 1.123325 673
## [8] 1.121433 476
看第一個關聯規則:「若身分是成人女性 => 則會存活」,lift=2.3 > 1,表示這個規則相當具有正相關;但其 support 卻沒有想像中的高,這也可以理解,因為當時那個年代,船上的女性人數應該遠低於男性人數,因此女性的樣本數較少,造成 support 較低也是合理的。
冗規則判斷與去除
然而,有發現到問題嗎?
第六個關聯規則(#編號8)「若身分是男性成人船員 => 不會存活」,對比於第五個關聯規則(#編號4):「若身分是男性船員 => 不會存活」,其實看不到任何有用的資訊!
而且,第六個規則的lift <= 第五個規則的lift, 當發生這樣的情況時,我們就可以說:第六個關聯規則是多餘的(redundant)。
多餘的關聯法則,會造成分析上的雜訊,因此需要刪除它們,但該怎麼做呢?
首先,先看某項規則是否為其他規則的子集(subset):(註,因套件版本的問題,函式回傳的矩陣有所改變,因此下面提供兩種不同的寫法,請依據自己的套件版本來撰寫)
# 先根據 support 大小排序 rules
sort.rule <- sort(rule, by="support")
# 'arules' version = 1.4-2 , under R-3.2.5
subset.matrix <- is.subset(x=sort.rule, y=sort.rule)
# 'arules' version = 1.5-2 , under R-3.4.0
subset.matrix <- as.matrix(is.subset(x=sort.rule, y=sort.rule))輸出的格式會像這樣:
上面的結果要解釋很簡單:在X的項目,如果是Y項目的子集(subset),就會回傳TRUE。
(當你用RStudio打開subset.matrix這個變數時,會看見一個8x8的矩陣)
之後再進行以下步驟:
# 把這個矩陣的下三角去除,只留上三角的資訊
subset.matrix[lower.tri(subset.matrix, diag=T)] <- NA
# 計算每個column中TRUE的個數,若有一個以上的TRUE,代表此column是多餘的
redundant <- colSums(subset.matrix, na.rm=T) >= 1
# 移除多餘的規則
sort.rule <- sort.rule[!redundant]
inspect(sort.rule)## lhs rhs support confidence lift
## [1] {Sex=Male,Age=Adult} => {Survived=No} 0.6038164 0.7972406 1.177669
## [2] {Class=Crew,Age=Adult} => {Survived=No} 0.3057701 0.7604520 1.123325
## [3] {Class=Crew,Sex=Male} => {Survived=No} 0.3044071 0.7772622 1.148157
## [4] {Class=3rd,Age=Adult} => {Survived=No} 0.2162653 0.7591707 1.121433
## [5] {Class=3rd,Sex=Male} => {Survived=No} 0.1917310 0.8274510 1.222295
## [6] {Sex=Female,Age=Adult} => {Survived=Yes} 0.1435711 0.7435294 2.301699
## count
## [1] 1329
## [2] 673
## [3] 670
## [4] 476
## [5] 422
## [6] 316
經過以上步驟後,多餘的規則消失了!
視覺化
在R裡面,關聯式規則還提供一個視覺化的套件arulesViz,可以觀察每條規則的三項指標分布情況:
require(arulesViz)
plot(sort.rule)而且也可以將規則視覺化,知道當初災難發生以後,在什麼樣的條件下比較容易存活/死亡:
plot(sort.rule, method="graph")plot(sort.rule, method="grouped")現在對照一開始的假設:「女性比較容易存活」、「男性船員幾乎死光光」、「3rd 客艙的成人幾乎無法存活」…嗯嗯嗯(點頭)!
不同的是,現在你的手上已經有證據了!因此下次跟別人一起看鐵達尼號時,就大方地拿來說嘴吧!
2. 決策樹(Decision Tree)
無論在分類或預測上,決策樹的演算法都有很好的效果。
但它最強大的地方,莫過於樹狀分支的結構:可以明顯呈現分類的規則!與一些機器學習的方法(NN, SVM…)相比,相當容易進行解釋,以及分析規則之間的關係。
rpart()建立決策樹
這裡就簡單用CART決策樹來練習,對應的套件是rpart,一樣使用剛才鐵達尼號的資料:
require(rpart)
# 先把資料區分成 train=0.8, test=0.2
set.seed(22)
train.index <- sample(x=1:nrow(titanic.raw), size=ceiling(0.8*nrow(titanic.raw) ))
train <- titanic.raw[train.index, ]
test <- titanic.raw[-train.index, ]
# CART的模型:把存活與否的變數(Survived)當作Y,剩下的變數當作X
cart.model<- rpart(Survived ~. ,
data=train)視覺化
要畫出決策樹(視覺化),雖然用平常的plot()就可以達成
但rpart有專屬的繪圖套件rpart.plot,函式是prp()
說真的,用prp()畫出來的決策樹,比較好看一些:
require(rpart.plot)
prp(cart.model, # 模型
faclen=0, # 呈現的變數不要縮寫
fallen.leaves=TRUE, # 讓樹枝以垂直方式呈現
shadow.col="gray", # 最下面的節點塗上陰影
# number of correct classifications / number of observations in that node
extra=2) (最下面節點的數字,代表:number of correct classifications / number of observations in that node)
根據以上決策樹,可以發現是男生或女生其實很重要(因為是第一個分支規則),其次是在船上的艙位等級。
因此,我們可以這樣解釋:
即使是女性,可是擁有的艙位若是最低下的(3rd),則大概有一半的死亡機率(82/155=53%);
但當妳的艙位高人一等時,則有相當高的存活機率(197/208=95%)。
又或者是:
當你是男性成人時,大概有八成機率會死(1084/1348=80%),合理推測剩下兩成是貴族(?)
以及
若是男性小孩,就和艙位等級有關:高級艙位的小孩全都獲救(13/13),可是低艙位的小孩有七成機率(26/37)會死。
(OS:男生好可憐QHQ 這個社會好現實QHQ)
預測
有決策樹之後,就要進行預測啦!
還記得在線性迴歸使用過的predict()嗎?這時就會派上用場囉(在這裡,會同時計算預測準確率):
pred <- predict(cart.model, newdata=test, type="class")
# 用table看預測的情況
table(real=test$Survived, predict=pred)## predict
## real No Yes
## No 278 9
## Yes 93 60
# 計算預測準確率 = 對角線的數量/總數量
confus.matrix <- table(real=test$Survived, predict=pred)
sum(diag(confus.matrix))/sum(confus.matrix) # 對角線的數量/總數量## [1] 0.7681818
3. 總結
和一些機器學習方法只會專注在「預測準確率」的概念不太一樣,,關聯式法則和決策樹在「解釋」上具有十分強大的優勢。
的確,在現實中,有時候確實只要「高的預測準確率」的模型,就可以達成許多目標。
可是也千萬別忘記了,我們正在進行的是「資料分析」,也就是去「解釋」資料中的故事。
事實上,有時候這個步驟反而會比「準確率」還重要。這一點,稍微思考一下就能理解了:唯有去探討資料的故事,才有機會發現到有趣的跡象、失敗的原因、違背直覺的現象……等等。
而且,這樣才有一種……真正在進行「資料分析」的感覺,不是嗎?
It’s still a long way to go~
5. R and packages version
這是本篇筆記使用R跟套件版本:
pkgs = c("arules", "arulesViz", "rpart.plot", "rpart")
r_version = paste("R", getRversion())
pkg_version = c()
for (package_name in pkgs) {
pkg_version = c(pkg_version,
paste(package_name,packageVersion(package_name)))
}
c(r_version, pkg_version)## [1] "R 3.4.3" "arules 1.5.5" "arulesViz 1.3.0"
## [4] "rpart.plot 2.1.2" "rpart 4.1.13"