1、創建虛擬變量
caret包通過model.matrix()、dummyVars()或其他方式將因子轉換為虛擬變量。
dummyVars()可用于從一個或多個因子變量生成一個完整的虛擬變量集。該函數獲取一個公式和一個數據集,并輸出一個對象,該對象創建虛擬變量可用于預測。
> library(pacman)
> p_load(earth, caret)
> data(etitanic)
> str(etitanic)
## 'data.frame': 1046 obs. of 6 variables:
## $ pclass : Factor w/ 3 levels "1st","2nd","3rd": 1 1 1 1 1 1 1 1 1 1 ...
## $ survived: int 1 1 0 0 0 1 1 0 1 0 ...
## $ sex : Factor w/ 2 levels "female","male": 1 2 1 2 1 2 1 2 1 2 ...
## $ age : num 29 0.917 2 30 25 ...
## $ sibsp : int 0 1 1 1 1 0 1 0 2 0 ...
## $ parch : int 0 2 2 2 2 0 0 0 0 0 ...
該數據集包括兩個因子變量,pclass表示乘客等級,sex表示性別。
看看R基本函數model.matrix()生成的結果:
> lm.mat <- model.matrix(survived ~ ., data = etitanic)
> head(lm.mat, 3)
## (Intercept) pclass2nd pclass3rd sexmale age sibsp parch
## 1 1 0 0 0 29.0000 0 0
## 2 1 0 0 1 0.9167 1 2
## 3 1 0 0 0 2.0000 1 2
再看看dummyVars()函數的結果:
> dummies <- dummyVars(survived ~ ., data = etitanic)
> pred.dummies <- predict(dummies, newdata = etitanic)
> head(pred.dummies, 3)
## pclass.1st pclass.2nd pclass.3rd sex.female sex.male age sibsp parch
## 1 1 0 0 1 0 29.0000 0 0
## 2 1 0 0 0 1 0.9167 1 2
## 3 1 0 0 1 0 2.0000 1 2
注意沒有截距項,每個級別的因子都有一個虛擬變量,所以這個參量化的函數對于某些模型可能沒有用處,比如lm()。
2、零方差和接近零方差變量的預測
在某些情況下,數據生成機制可以創建只有一個唯一值的預測因子(即“零方差預測器”)。 對于許多模型(不包括基于樹的模型) ,這可能會導致模型崩潰或擬合得不健壯。
> data(mdrr)
> table(mdrrDescr$nR11)
##
## 0 1 2
## 501 4 23
數據集中可能只有少數值出現的頻率很低,非常的不平衡。當使用交叉驗證建模時,這些樣本可能對模型的影響很小而成為零方差預測因子。
nearZeroVar()函數用來識別常數自變量,或者是方差極小的自變量:
> # saveMetrics默認為F,用來顯示細節
> nzv <- nearZeroVar(mdrrDescr,
+ # 第一眾數與第二眾數的比率的cutoff(臨界值)
+ freqCut = 95/5,
+ # 剔重后的唯一值 與 樣本總數量的百分比,大于這個值不會被剔除
+ uniqueCut = 10,
+ saveMetrics = T)
> str(nzv)
## 'data.frame': 342 obs. of 4 variables:
## $ freqRatio : num 1.25 1.12 1 1.25 1.25 ...
## $ percentUnique: num 90 42.6 83 84.3 82.8 ...
## $ zeroVar : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
## $ nzv : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
> # 顯示前10個接近零方差的變量
> nzv[nzv$nzv,][1:10,]
## freqRatio percentUnique zeroVar nzv
## nTB 23.00000 0.3787879 FALSE TRUE
## nBR 131.00000 0.3787879 FALSE TRUE
## nI 527.00000 0.3787879 FALSE TRUE
## nR03 527.00000 0.3787879 FALSE TRUE
## nR08 527.00000 0.3787879 FALSE TRUE
## nR11 21.78261 0.5681818 FALSE TRUE
## nR12 57.66667 0.3787879 FALSE TRUE
## D.Dr03 527.00000 0.3787879 FALSE TRUE
## D.Dr07 123.50000 5.8712121 FALSE TRUE
## D.Dr08 527.00000 0.3787879 FALSE TRUE
> dim(mdrrDescr)
## [1] 528 342
> index <- nearZeroVar(mdrrDescr)
> filter.Descr <- mdrrDescr[, -index]
> dim(filter.Descr)
## [1] 528 297
可以看到,數據由342個變量刪減為297個變量了。
3、識別與其他變量有強相關性的變量
> # 建立相關性矩陣
> descr.cor <- cor(filter.Descr)
> summary(descr.cor[upper.tri(descr.cor)])
查看相關性統計信息:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.99607 -0.05373 0.25006 0.26078 0.65527 1.00000
> # 找出相關性高于0.75的變量
> high.cor <- findCorrelation(descr.cor, cutoff = 0.75)
> length(high.cor)
## [1] 247
一共247個變量,與其他變量的相關性高于0.75。
> low.cor <- filter.Descr[, -high.cor]
> descr.cor.2 <- cor(low.cor)
> summary(descr.cor.2[upper.tri(descr.cor.2)])
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.70728 -0.05378 0.04418 0.06692 0.18858 0.74458
剔除后再看看相關性統計信息,全部在0.75以下了。
4、識別變量共線性
> mat <- matrix(0, nrow = 6, ncol = 6)
> mat[, 1] <- c(1, 1, 1, 1, 1, 1)
> mat[, 2] <- c(1, 1, 1, 0, 0, 0)
> mat[, 3] <- c(0, 0, 0, 1, 1, 1)
> mat[, 4] <- c(1, 0, 0, 1, 0, 0)
> mat[, 5] <- c(0, 1, 0, 0, 1, 0)
> mat[, 6] <- c(0, 0, 1, 0, 0, 1)
請注意,第二列和第三列相加就等于第一列。同樣,第四、五和六列加起來就是第一列。Findlinearcombos()函數將返回一個列表,列舉這些依賴項。對于每個線性組合,它都會遞增地從矩陣中刪除列,并測試依賴關系是否已被解析。還將返回一個列位置的向量,以消除線性依賴:
> combo.info <- findLinearCombos(mat)
> combo.info
## $linearCombos
## $linearCombos[[1]]
## [1] 3 1 2
##
## $linearCombos[[2]]
## [1] 6 1 4 5
##
##
## $remove
## [1] 3 6
> mat <- mat[, -combo.info$remove]
> mat
## [,1] [,2] [,3] [,4]
## [1,] 1 1 1 0
## [2,] 1 1 0 1
## [3,] 1 1 0 0
## [4,] 1 0 1 0
## [5,] 1 0 0 1
## [6,] 1 0 0 0
5、preProcess函數
缺省參數是標準化數據,其高級功能還包括用K近鄰和裝袋決策樹兩種方法來預測缺失值。此外它還可以進行cox冪變換和主成分提取。
method為處理方法,可能的值為"BoxCox", "YeoJohnson", "expoTrans", "center", "scale", "range", "knnImpute", "bagImpute", "medianImpute", "pca", "ica", "spatialSign", "corr", "zv", "nzv", "conditionalX"。
BoxCox 變換用于響應變量的轉換,對于估計冪變換也同樣有效
YeoJohnson 轉換類似于 Box-Cox 模型,但是可以容納零和 / 或負值的預測器(BoxCox 轉換的預測器值必須嚴格為正)
center 預測值減去預測值數據的平均值
scale 預測值除以預測值數據的標準差
range 轉換擴展了范圍內的數據。 如果新樣本的值大于或小于訓練集中的值,則值將超出此范圍。在計算中將忽略非數值型預測值。
zv 用單個值(即方差為零)標識數值型預測列,并將其排除在進一步計算之外
nzv 通過應用nearZeroVar函數標識方差接近0的變量,并將其排除在進一步計算之外
除非使用zv或者nzv方法,否則任何數值型變量少于2個唯一值時函數將報錯
corr 通過findCorrelation函數過濾掉高度相關的預測因子
conditionalX 對于分類,根據結果檢查每個預測因子的分布情況。如果某類中只有一個唯一值,則預測器將被排除在進一步計算之外。如果預測的不是因子變量,則不執行此計算。 這個操作在通過train函數進行重采樣時會很耗時。
運算按如下順序進行: zero-variance filter, near-zero variance filter, correlation filter, Box-Cox/Yeo-Johnson/exponential transformation, centering, scaling, range, imputation, PCA, ICA then spatial sign.
使用PCA和ICA方法時,數據將被自動中心化和標準化。如果同時使用PCA和ICA方法,則會拋出警告。Ica由fastICA包實現,在查找ICA得分之前自動進行PCA分解
注意,當使用PCA或ICA時,非數值型變量在預測時可能位于不同的位置。非數值型數據不會被預處理,但是他們的值會保留在預測值中。
knnImpute 通過訓練集的K最近鄰(歐式距離)填充缺失值
bagImpute 通過裝袋法填充缺失值,該方法簡單、準確、可接受缺失值,但是計算量大
medianImpute 通過訓練集中預測值的中位數填充缺失值,該方法簡單、快速、可接受缺失值,但可能不準確
5.1 中心化和標準化
> set.seed(120)
> ind <- sample(2, nrow(low.cor), replace = T, prob = c(0.7, 0.3))
>
> train <- low.cor[ind == 1, ]
> test <- low.cor[ind == 2, ]
>
> dim(train)
## [1] 367 50
> dim(test)
## [1] 161 50
> # 同時使用多種預處理方法
> preprocess.values <- preProcess(train,
+ method = c("center", "scale", "YeoJohnson", "nzv"))
> preprocess.values
## Created from 367 samples and 50 variables
##
## Pre-processing:
## - centered (50)
## - ignored (0)
## - scaled (50)
## - Yeo-Johnson transformation (31)
##
## Lambda estimates for Yeo-Johnson transformation:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -2.70101 -0.41917 0.04850 -0.07775 0.35785 1.88606
> train.transformed <- predict(preprocess.values, train)
> test.transformed <- predict(preprocess.values, test)
>
> train[1:3, 1:3]
## AMW Mp Ms
## METHOPROMAZINE 7.15 0.67 1.92
## ACEPROMAZINE 7.26 0.68 2.06
## TRIMEPRAZINE 6.94 0.68 1.85
> train.transformed[1:3, 1:3]
## AMW Mp Ms
## METHOPROMAZINE 0.322580832 0.5994524 -0.9359891
## ACEPROMAZINE 0.480970227 0.9717011 -0.3131278
## TRIMEPRAZINE 0.007559779 0.9717011 -1.2474198
5.2 特征選擇
在進行數據挖掘時,我們并不需要將所有的自變量用來建模,而是從中選擇若干最重要的變量,這稱為特征選擇(feature selection)。一種算法是后向選擇,即先將所有的變量都包括在模型中,然后計算其效能(如誤差、預測精度)和變量重要排序,然后保留最重要的若干變量,再次計算效能,這樣反復迭代,找出合適的自變量數目。這種算法的一個缺點在于可能會存在過度擬合,所以需要在此算法外再套上一個樣本劃分的循環。在caret包中的rfe()函數可以完成這項任務。
> # functions確定用什么樣的模型進行自變量排序,本例選擇的模型是隨機森林即rfFuncs
> # 可以選擇的還有lmFuncs(線性回歸),nbFuncs(樸素貝葉斯),treebagFuncs(裝袋決策樹),caretFuncs(使用caret包的訓練模型)
> # method確定用什么樣的抽樣方法,本例使用cv即交叉檢驗
> # 還有提升boot以及留一交叉檢驗LOOCV
> ctrl <- rfeControl(functions = rfFuncs,
+ # 確定抽樣方法,默認為“boot”
+ method = "repeatedcv",
+ verbose = F,
+ # 交叉驗證折數或抽樣迭代次數,默認10和25
+ number = 20,
+ returnResamp = "final")
>
> # 使用隨機森林算法,設置多線程(linux系統)
> if (require("multicore", quietly = TRUE, warn.conflicts = FALSE)) {
+ ctrl$workers <- multicore:::detectCores()
+ ctrl$computeFunction <- mclapply
+ ctrl$computeArgs <- list(mc.preschedule = FALSE, mc.set.seed = FALSE)
+ }
>
> # 特征選擇
> profile <- rfe(
+ # 訓練集自變量矩陣或數據庫,注意,列名必須唯一
+ train.transformed,
+ # 訓練集的結果向量(數值型或因子型)
+ mdrrClass[ind==1],
+ # 指定選擇最優模型的指標,默認分類用Acc,回歸用RMSE
+ metric = "Accuracy",
+ # metric是否最大化,"Accuracy"為T,RMSE為F
+ maximize = T,
+ # 控制項列表,包括擬合預測的函數
+ rfeControl = ctrl,
+ rerank=F)
> profile
##
## Recursive feature selection
##
## Outer resampling method: Cross-Validated (20 fold, repeated 1 times)
##
## Resampling performance over subset size:
##
## Variables Accuracy Kappa AccuracySD KappaSD Selected
## 4 0.7744 0.5374 0.07025 0.1434
## 8 0.8234 0.6376 0.07440 0.1559
## 16 0.8311 0.6544 0.06564 0.1292 *
## 50 0.8311 0.6539 0.05745 0.1134
##
## The top 5 variables (out of 16):
## X5v, VRA1, H3D, G1, QXXm
最終選擇了16個變量。畫圖看看重要性排序:
> plot(profile)
可以看到16個變量時效能最高。返回最終保留的自變量:
> profile$optVariables
## [1] "X5v" "VRA1" "H3D" "G1" "QXXm" "Xt" "nBnz" "Jhetm" "SPAM"
## [10] "TIE" "nAB" "FDI" "VEA1" "BLI" "SPI" "SPH"