扎心實戰案例:麻(shi)雀(zhan)雖小,五臟俱全

R語言中文社群發表於2018-03-07


640?wx_fmt=gif

作者簡介Introduction

鄔書豪,車聯網資料探勘工程師 ,R語言中文社群專欄作者。微信ID:tsaiedu

知乎專欄:https://www.zhihu.com/people/wu-shu-hao-67/activities


往期回顧

kaggle:資料科學社群調查報告(附學習視訊)

kaggle:員工離職預測(附學習視訊)

Kaggle:紐約的士旅程資料簡要分析

Kaggle:R視覺化分析美國槍擊案(附資料集和程式碼)

共享單車租用頻次分析

640?wx_fmt=png

640?wx_fmt=jpeg

首先呢,猜測一下家的心思:這個推文是啥,標題這麼奇怪;哇,推文開頭的玻璃(還是碎玻璃)是啥?!還能不能看下去啊......

放心吧,能看的。這是一個對玻璃進行分類的問題,而且還是多分類不平衡問題。雖然說大家對玻璃並沒有啥興趣,但是實戰內容還是可以的哦。

廢話不說,直直直奔主題了!!!

本次實戰大致包括五部分:

  • 視覺化

  • 分層抽樣

  • 決策樹

  • 隨機森林

  • 特徵選擇+隨機森林

## 載入後續分析所需程式包

## 載入所需的程式包

library(ggplot2)
library(Rmisc)
library(caret)

## 讀取資料+簡單探索

## 讀取資料+簡單探索
glass <- read.csv('../input/glass.csv')

str(glass)
summary(glass)
head(glass)

640?wx_fmt=png

通過str函式對資料集進行簡單的結構探索,我們可以得到三個重要資訊:

·匯入的資料集是資料框型別

·該資料集有214行,10列

·所有變數均是數值

640?wx_fmt=png

通過summary函式對資料集進行統計主要描述性統計量,我們得到了最小值、中位數、最大值等統計量,方便我們在一定程度上發現各個變數是否存在異常值(最終還得通過業務去決定)。

640?wx_fmt=png

通過head函式,可以展示資料集的前六行。通過這三個函式,就可以大致對整個資料集產生一個輪廓。細心的人到這裡就會發現,到底是幾類啊,每一類有多少個樣本啊,通過簡單的探索也沒體現處理啊?!不著急,進行簡單的探索之後,下一步就用圖去探索一些上面為表達出的資訊,俗話說的好“能用圖不用表,能用表不用文字”。


## 描述性分析

## 探索不同類別的個數
glass$Type <- as.factor(glass$Type)

ggplot(glass, aes(x = Type, fill = Type)) +
 geom_bar(width = 0.7) +
 labs(x = 'Type', y = 'Count', title = 'The Number Of Different Types') +
 theme_bw() +
 theme(axis.text = element_text(size = rel(1)),
       axis.title = element_text(size = rel(1.1)),
       plot.title = element_text(size = rel(1.4), hjust = 0.5)) +
 guides(fill = 'none')

640?wx_fmt=png

看到這個圖,想必上面關於類別的疑問也就得到答覆了:一共6類,而且類別不平衡。到這裡不得不說一句,其實如果想簡單粗暴的檢視類別的資訊,可以直接使用table(glass$Type)去統計,但是呢,表現出來的效果不同,不同場合使用不同的方式才使最好的。接下來就使用箱線圖去探索一下每個自變數與因變數的關係。

## 箱線圖---variables VS type
var_names <- names(glass[-10])
gp <- lapply(var_names, function(x) {
 ggplot(glass, aes(x = Type, y = eval(parse(text = x)), fill = Type)) +
   geom_boxplot() +
   labs(y = x, title = paste(x, "VS Type", sep = " ")) +
   theme_bw() +
   theme(axis.text = element_text(size = rel(1)),
         axis.title = element_text(size = rel(1.1)),
         plot.title = element_text(size = rel(1.2), hjust = 0.5)) +
   guides(fill = 'none')
})

multiplot(plotlist = gp[1:6], cols = 2)
multiplot(plotlist = gp[7:9], cols = 3)

640?wx_fmt=png

640?wx_fmt=png

上面的9個箱線圖中有幾個比較醜,由於對業務的不熟悉和節省篇幅,所以我就不剔除離群點在進行繪圖了,有強迫症的可以自己剔除之後在繪圖。

通過這幾個圖呢,大致能看出不同的類別中不同元素和折射率的分佈情況。從一定程度上而言,變數分佈差距越明顯,那麼用該變數就更容易區分類別。再次宣告:本人不是從事玻璃行業的,不清楚業務問題,所以就不進行“異常值”的處理了,後續直接建模......


## 分層抽樣

分層抽樣是在不平衡分類問題中常用的一種抽樣方法,分層抽樣後的資料與原資料的分佈幾乎一致,也就意味著在此時屬於有效抽樣。

## 建立訓練集和測試集
set.seed(1234)
idx <- createDataPartition(glass$Type, p = 0.7, list = F)
traindata <- glass[idx, ]
testdata <- glass[-idx, ]

round(prop.table(table(glass$Type)), 3)
round(prop.table(table(traindata$Type)), 3)
round(prop.table(table(testdata$Type)), 3)

640?wx_fmt=png

從上圖可以看出,不同的類別在原資料、訓練集和測試集中佔比還是比較一致的。由於資料集樣本較少,比例稍有差距,否則比例趨近一致。


#### 建模分類

## 決策樹

## 決策樹
ctrl <- trainControl(method = 'boot632', selectionFunction = 'oneSE')

set.seed(1234)
model_C50 <- train(Type ~., data = traindata, method = 'C5.0', trControl = ctrl)

pred_C50 <- predict(model_C50, testdata[-10])
confusionMatrix(pred_C50, testdata$Type)  # 0.8361--0.7683

640?wx_fmt=png

雖然說混淆矩陣的整體正確率不適合去評估類別不平衡的分類問題,但是並不是絕對的。通過此混淆矩陣的結果,可以看出類別少的樣本也有不錯的分類效果,所以說此混淆矩陣在這裡也是合適的,並且kappa值也達到了0.7683,說明模型達到了不錯的一致性。


## 隨機森林

## 隨機森林
set.seed(1234)
model_rf <- train(Type ~., data = traindata, method = 'rf', trControl = ctrl)

pred_rf <- predict(model_rf, testdata[-10])
confusionMatrix(pred_rf, testdata$Type)  # 0.8361--0.7673

640?wx_fmt=png

隨機森林的正確率也是0.8361,但是通過混淆矩陣的詳細情況,可發現預測的類別並不相同。kappa值為0.7673,略比決策樹低一點點。整體而言,隨機森林模型稍遜於決策樹模型。


## 特徵選擇+隨機森林

特徵選擇,簡而言之就是篩選出一些高質量的自變數作為最終建立模型的自變數,從而不僅降低模型的複雜度,並且防止過擬合的產生。

rfeControls_rf <- rfeControl(
 functions = rfFuncs,
 method = 'boot')

set.seed(1)
profile_rf <- rfe(x = traindata[-10],
                 y = traindata[, 10],
                 sizes = seq(4, 9, 1),
                 rfeControl = rfeControls_rf)

profile_rf

640?wx_fmt=png

經過自定義特徵選擇之後,發現使用8個自變數作為建模變數為此時最好的選擇,所以我們嘗試使用8個自變數建模。

vars_new <- c(profile_rf$optVariables, 'Type')

set.seed(1234)
model_rf2 <- train(Type ~.,
                  data = traindata[vars_new],
                  method = 'rf',
                  trControl = ctrl)

pred_rf2 <- predict(model_rf2, testdata[-10])
confusionMatrix(pred_rf2, testdata$Type)  # 0.8525--0.7905

640?wx_fmt=png

經過特徵選擇,正確率稍微高了一點點。經過觀察混淆矩陣,發現第2類玻璃全部分類正確,之前預測錯了一個樣本,總而言之,也是提高了,並且模型的複雜度和過擬合性也有所降低。

到最後了,好像忘了一個重要的問題,玻璃的類別詳情如下:

  • 1 building_windows_float_processed

  • 2 building_windows_non_float_processed

  • 3 vehicle_windows_float_processed

  • 4 vehicle_windows_non_float_processed (none in this database)

  • 5 containers 

  • 6 tableware

  • 7 headlamps

注:本案例不提供資料集,如果要學習完整案例,點選文章底部閱讀原文或者掃描課程二維碼,購買包含資料集+程式碼+PPT的《kaggle十大案例精講課程》,購買學員會贈送文章的資料集。

《kaggle十大案例精講課程》提供程式碼+資料集+詳細程式碼註釋+老師講解PPT!綜合性的提高你的資料能力,資料處理+資料視覺化+建模一氣呵成!

相關課程推薦


Kaggle十大案例精講課程(連載中)

640?wx_fmt=jpeg

相關文章