一、创建哑变量
如果你有一个因子型变量需要进行哑变量处理,你会怎么办?也许你会根据该变量的m个水平数构建m-1个哑变量,不错,这样的思路是没有问题的。但如果发现该变量确实很重要,而且水平数目非常多,那你一定会抓狂!如果你会caret包中的dummyVars()函数,那将如虎添翼,效率倍增~我们来看看该函数是如何实现哑变量构建的。
函数语法及参数介绍:
dummyVars(formula, data, sep = ".",levelsOnly = FALSE, fullRank = FALSE, ...)
predict(object, newdata, na.action = na.pass, ...)
formula: 公式右边请指定需要处理为哑变量的因子型变量
sep:设置变量与水平间的分割符,默认为实心点。如x.a,x就是变量名,a就是x的一个水平
levelsOnly:逻辑值,如果为True,则列名中剔除原变量名。如x.a变为a,把因子作为变量名
object:为dummyVars()函数构成的结果
newdata:需要处理的新数据
na.action:缺失值的对待,变量水平中如果有缺失值,则结果仍为缺失值
library(caret)
dummy <- dummyVars(formula = ~ ., data = iris,levelsOnly=TRUE)#把因子作为变量名
pred <- predict(dummy, newdata = iris)
head(pred)
## Sepal.Length Sepal.Width Petal.Length Petal.Width setosa versicolor virginica
## 1 5.1 3.5 1.4 0.2 1 0 0
## 2 4.9 3.0 1.4 0.2 1 0 0
## 3 4.7 3.2 1.3 0.2 1 0 0
## 4 4.6 3.1 1.5 0.2 1 0 0
## 5 5.0 3.6 1.4 0.2 1 0 0
## 6 5.4 3.9 1.7 0.4 1 0 0
如果有很多因子变量需要转换为哑变量呢?
set.seed(1234)
f1 <- sample(c('a','b','c'),100,replace = T)
f2 <- sample(c('f','m'),100,replace = T)
f3 <- sample(c('h','m','l'),100,replace = T)
x <- round(runif(100,1,10))
df <- data.frame(x = x, f1 = f1, f2 = f2, f3 = f3)
#可以直接用下面的方法一步搞定,和上面一样非常方便
dummy=dummyVars(formula = ~.,data=df)#不是因子变量得自动过滤
pred <- predict(dummy, newdata = df)
head(pred)
## x f1a f1b f1c f2f f2m f3h f3l f3m
## 1 7 0 1 0 0 1 0 0 1
## 2 3 0 1 0 1 0 0 1 0
## 3 8 1 0 0 0 1 0 0 1
## 4 8 0 0 1 1 0 0 1 0
## 5 10 1 0 0 0 1 0 1 0
## 6 3 1 0 0 0 1 0 1 0
二、近零方差变量的删除
数据集中有某些变量的值非常稀少,而其他值可能又很多,例如性别字段,共有1000个观测,女只有10个观测,男990个观测,一般直接删除该变量,若有很多呢?
数语法及参数介绍:
nearZeroVar(x, freqCut = 95/5, uniqueCut = 10, saveMetrics = FALSE,
names = FALSE,foreach = FALSE, allowParallel = TRUE)
nzv(x, freqCut = 95/5, uniqueCut = 10, saveMetrics = FALSE, names = FALSE)
x:为一个向量或矩阵或数据框,需要注意的是,必须是数值型对象,
- 如果是字符型的变量,建议转换为数值型的值,可通过factor函数实现
- 如果是字符型的变量,建议转换为数值型的值,可通过factor函数实现
freqCut:为一个阈值,默认值为95/5,即最频繁的数值个数除以次频繁的数值个数。
- 如上面的性别字段,990/10>95/5
- 如上面的性别字段,990/10>95/5
uniqueCut:为一个阈值,默认值为10%,即某个变量中不同值的个数除以样本总量。
- 如上面的性别字段,2/1000<0.1(根据近零方差的判断标准是,如果某个变量的freqCut超过了给到的默认阈值,并且uniqueCut低于给到的默认阈值,就认为改变量是近零方差的。)
- 如上面的性别字段,2/1000<0.1(根据近零方差的判断标准是,如果某个变量的freqCut超过了给到的默认阈值,并且uniqueCut低于给到的默认阈值,就认为改变量是近零方差的。)
saveMetrics:逻辑值,默认为False,
- 如果为True的话会返回一个统计表,反映每个变量是否为零方差和近零方差
names:逻辑值,默认为False,
- 如果为True的话,返回零方差和近零方差的变量名,否则返回对应的索引值
- 如果为True的话,返回零方差和近零方差的变量名,否则返回对应的索引值
foreach:是否指定使用foreach包进行计算,如果使用,计算过程将消耗更少的内存,但会比较耗时间
allowParallel:是否指定使用foreach包进行并行运算,如果使用,将会消耗更多内存,但执行时间将更少
data(mdrr)# 加载数据mdrr,得到的数据框竟是mdrrDescr
data.frame(table(mdrrDescr$nR11)) #某个变量的观测频率分布
## Var1 Freq
## 1 0 501
## 2 1 4
## 3 2 23
dim(mdrrDescr)# 原数据维度
## [1] 528 342
#方法1
df <- nearZeroVar(mdrrDescr, saveMetrics= TRUE)#得到一个数据框
df[df$nzv,][1:10,]#df$nzv为逻辑值,选择TRUE的,为领方差变量
## 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
sum(df$nzv)#零方差变量为TURE的个数为45
## [1] 45
filterdf = mdrrDescr[,!df$nzv] #剔除零方差变量
# 方法2
nzv <- nearZeroVar(mdrrDescr) #直接得到一个向量,零方差变量得序号列
filteredDescr <- mdrrDescr[,-nzv] #剔除零方差变量
dim(filteredDescr)
## [1] 528 297
all(filterdf==filteredDescr)
## [1] TRUE
三、删除高相关的预测变量和完全线性关系的变量
在某些模型算法中就明确要求变量间不能有高度线性相关的变量,因为这会导致模型非常敏感与不稳定,例如线性回归模型或基于最小二乘方法的其他模型一般度要求变量间尽量不存在线性相关性。那问题来了,我该如何检验并剔除高相关的变量呢?
findCorrelation(x, cutoff = .90, verbose = FALSE,names = FALSE, exact = ncol(x) < 100)
x:为一个相关系数矩阵
cutoff:指定高度线性相关的临界值,默认为0.9
verbose:逻辑值,指定是否打印出函数运算的详细结果
names:逻辑值,是否返回变量名,默认返回需要删除变量的对应索引值
exact:逻辑值,是否重新计算每一步的平均相关系数
#返回相关系数矩阵中的上三角值
corr <- cor(iris[,1:4])
corr[upper.tri(corr)]
## [1] -0.1175698 0.8717538 -0.4284401 0.8179411 -0.3661259 0.9628654
#虽然能够一幕了然的看到那些相关系数是高相关的,但不能明确那组变量间是高相关的。
#
fC = findCorrelation(corr, cutoff = .8)
fC
## [1] 3 4
head(iris[fC])
## Petal.Length Petal.Width
## 1 1.4 0.2
## 2 1.4 0.2
## 3 1.3 0.2
## 4 1.5 0.2
## 5 1.4 0.2
## 6 1.7 0.4
head(iris[-fC])
## Sepal.Length Sepal.Width Species
## 1 5.1 3.5 setosa
## 2 4.9 3.0 setosa
## 3 4.7 3.2 setosa
## 4 4.6 3.1 setosa
## 5 5.0 3.6 setosa
## 6 5.4 3.9 setosa
3.1 矩阵的线性相关
ltfrDesign <- matrix(0, nrow=6, ncol=6)
ltfrDesign[,1] <- c(1, 1, 1, 1, 1, 1)
ltfrDesign[,2] <- c(1, 1, 1, 0, 0, 0)
ltfrDesign[,3] <- c(0, 0, 0, 1, 1, 1)
ltfrDesign[,4] <- c(1, 0, 0, 1, 0, 0)
ltfrDesign[,5] <- c(0, 1, 0, 0, 1, 0)
ltfrDesign[,6] <- c(0, 0, 1, 0, 0, 1)
comboInfo <- findLinearCombos(ltfrDesign)#返回一个列表,是列向量的索引
comboInfo
## $linearCombos
## $linearCombos[[1]]
## [1] 3 1 2
##
## $linearCombos[[2]]
## [1] 6 1 4 5
##
##
## $remove
## [1] 3 6
ltfrDesign[, -comboInfo$remove] #移除线性依赖相关的向量
## [,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
四、数据标准化处理 preProcess()函数
参考其他资料,我讲讲其他的
五、缺失数据的处理
可以用preProcess()函数,该函数提供了三种缺失值填补的方法,即K近邻方法、Bagging树集成方法和中位数法。
需要注意的是,采用K近邻方法时,会对原始数据进行标准化,如果需要返回原始值,还需将标准化公式倒推回来;使用Bagging树集成方法,理论上对缺失值的填补更权威,但其效率比较低;使用中位数方法,速度非常快,但填补的准确率有待验证。如果你想使用多重插补法,不妨也可以试试mice包,其操作原理是基于MC(蒙特卡洛模拟法)。
set.seed(1234)
y <- runif(1000,1,10)
x1 <- 2 - 1.32*y + rnorm(1000)
x2 <- 1.3 + 0.8 * y + rnorm(1000)
df <- data.frame(y = y, x1 = x1, x2 = x2)
#对y变量随机构造一些缺失值
df$y[sample(1000,26)] <- NA
summary(df$y)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1.003 3.323 5.585 5.564 7.832 9.994 26
#k临近替补法
imputation_k <- preProcess(df,method = 'knnImpute')
pred_k <- predict(imputation_k, df)
summary(pred_k$y)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -1.736229 -0.852905 0.010604 0.000577 0.863056 1.686379
#bagging树替补法
imputation_bag <- preProcess(df,method = 'bagImpute')
pred_bag <- predict(imputation_bag, df)
summary(pred_bag$y)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.003 3.323 5.592 5.566 7.826 9.994
#中位数替补法
imputation_m <- preProcess(df,method = 'medianImpute')
pred_m <- predict(imputation_m, df)
summary(pred_m$y)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.003 3.379 5.585 5.564 7.774 9.994
六、变量转换
preProcess()函数也可以帮助我们实现变量的转换,例如降维操作,降维的目的是考虑到变量太多,通过降维能使主成分之间不相关或独立,而且还保留了数据绝大部分信息。我们常见的PCA和ICA就是用于降维,通过设置preProcess()函数的method参数就可方便的实现变量的降维操作。
当method=‘pca’时,就是指定主成分分析法实现数据的降维,原数据集的变量会改为P1,P2…,而且该方法也会强制原始数据进行标准化处理;
当method=‘ica’时,就是指定独立成分分析法实现数据的降维,原数据集的变量会改为IC1,IC2,…。
x1 <- c(5700,1000,3400,3800,4000,8200,1200,9100,9900,9600,9600,9400)
x2 <- c(12.8,10.9,8.8,13.6,12.8,8.3,11.4,11.5,12.5,13.7,9.6,11.4)
x3 <- c(2500,600,1000,1700,1600,2600,400,3300,3400,3600,3300,4000)
x4 <- c(270,10,10,140,140,60,10,60,180,390,80,100)
x5 <- c(25000,10000,9000,25000,25000,12000,16000,14000,18000,25000,12000,13000)
my_data <- data.frame(x1 = x1, x2 = x2, x3 = x3, x4 = x4, x5 = x5)
#pca
pca <- preProcess(my_data, pcaComp = 2, method = 'pca')
pred_pca <- predict(pca, newdata = my_data)
head(pred_pca)
## PC1 PC2
## 1 1.6436740 -0.9551928
## 2 -2.2569672 -1.0170973
## 3 -2.4952117 0.1203249
## 4 0.7791262 -1.7305754
## 5 0.5644634 -1.5572479
## 6 -1.1730558 1.5417414
ica <- preProcess(my_data,n.comp= 2, method = 'ica')
pred_ica <- predict(ica, newdata = my_data)
head(pred_ica)
## ICA1 ICA2
## 1 -0.08532044 1.2539749
## 2 -1.41459576 -0.7490288
## 3 -0.74513359 -1.3481169
## 4 -0.88094458 1.1282154
## 5 -0.83784724 0.9441523
## 6 0.62660219 -1.2542253
七、数据分割
7.1 简单的抽样—createDataPartition()
函数语法及参数介绍:
createDataPartition(y, times = 1, p = 0.5,list = TRUE,groups = min(5, length(y)))
y: 指定数据集中的输出变量
times: 指定创建的样本个数,默认简单随机抽取一组样本
p: 指定数据集中用于训练集的比例
list: 是否已列表或矩阵的形式存储随机抽取的索引号,默认为TRUE
groups: 如果输出变量为数值型数据,则默认按分位数分组进行取样
idx2 <- createDataPartition(iris$Species, p = 0.8, list = FALSE)
#设置p=0.8时,就隐含了两层含义,即从总体中抽取80%的样本,同时在各个因子水平下也取80%的样本
train2 <- iris[idx2,]
test2 <- iris[-idx2,]
7.2 使用有放回的方法进行抽样(BootStrap)
createResample(y, times = 10, list = TRUE)
y:指定数据集中的输出变量
times:指定抽样组数,默认为10组
list:是否已列表或矩阵的形式存储随机抽取的索引号,默认为TRUE
createResample(iris[,5], times = 2, list = TRUE)
## $Resample1
## [1] 1 3 4 4 5 5 6 7 8 8 9 10 11 13 13 14 16 16
## [19] 18 20 23 24 24 24 26 26 28 29 31 33 33 34 34 37 37 37
## [37] 38 42 44 45 47 48 52 54 57 60 61 62 63 63 64 65 66 66
## [55] 68 69 70 70 71 74 74 74 75 76 76 78 79 80 80 80 83 83
## [73] 84 87 87 89 89 92 93 93 93 94 95 95 96 96 96 96 97 99
## [91] 100 100 100 101 101 103 104 106 106 106 107 108 112 112 113 113 113 115
## [109] 116 116 116 116 117 117 117 118 119 121 123 124 125 125 125 126 126 126
## [127] 127 127 128 130 131 132 132 133 134 134 134 135 136 137 137 137 138 138
## [145] 141 144 144 145 148 150
##
## $Resample2
## [1] 1 1 1 1 3 4 4 6 6 6 6 6 11 11 14 16 17 18
## [19] 22 23 24 26 28 29 30 30 30 30 31 31 34 35 36 36 36 38
## [37] 38 41 42 43 43 44 44 46 47 47 49 51 51 51 51 52 52 53
## [55] 54 55 55 56 56 60 61 62 62 63 64 66 67 68 69 72 74 74
## [73] 75 76 77 77 78 80 83 84 85 86 87 87 89 89 89 91 91 92
## [91] 92 96 96 98 99 100 102 102 102 105 106 106 108 108 109 110 112 114
## [109] 115 115 116 116 116 118 119 121 121 122 122 123 123 125 125 126 127 128
## [127] 128 129 130 131 131 132 132 133 134 134 140 141 141 142 142 143 144 147
## [145] 148 149 150 150 150 150
7.3 用于交叉验证的样本抽样
createFolds(y, k = 10, list = TRUE, returnTrain = FALSE)
createMultiFolds(y, k = 10, times = 5)
y:指定数据集中的输出变量
k:指定k重交叉验证的样本,默认为10重。每重的样本量为总量/k。
list:是否已列表或矩阵的形式存储随机抽取的索引号,默认为TRUE
returnTrain:是否返回抽样的真实值,默认返回样本的索引值
times:指定抽样组数,默认为5组(每组中都有10重抽样)
createFolds(iris[,5], k = 2, list = TRUE, returnTrain = F)
## $Fold1
## [1] 5 13 15 16 17 21 22 23 24 26 27 28 29 30 33 34 35 36 43
## [20] 44 45 47 48 49 50 51 52 54 58 59 60 61 62 67 68 69 72 73
## [39] 75 76 80 81 83 86 91 92 93 96 97 100 101 102 109 110 111 112 113
## [58] 117 121 124 126 127 130 132 134 135 136 137 138 139 140 141 143 144 149
##
## $Fold2
## [1] 1 2 3 4 6 7 8 9 10 11 12 14 18 19 20 25 31 32 37
## [20] 38 39 40 41 42 46 53 55 56 57 63 64 65 66 70 71 74 77 78
## [39] 79 82 84 85 87 88 89 90 94 95 98 99 103 104 105 106 107 108 114
## [58] 115 116 118 119 120 122 123 125 128 129 131 133 142 145 146 147 148 150
# 产生多个交叉验证的数据指标索引
createMultiFolds(iris[,5], k = 2, times = 2)
## $Fold1.Rep1
## [1] 1 3 5 6 9 11 13 14 16 18 19 23 25 26 27 31 33 34 36
## [20] 41 42 43 44 45 46 52 53 54 55 56 60 71 72 74 77 80 81 82
## [39] 84 85 86 88 89 90 94 95 96 97 98 99 102 104 105 106 112 113 114
## [58] 117 118 119 120 121 123 125 129 131 132 133 136 138 140 145 146 147 148
##
## $Fold2.Rep1
## [1] 2 4 7 8 10 12 15 17 20 21 22 24 28 29 30 32 35 37 38
## [20] 39 40 47 48 49 50 51 57 58 59 61 62 63 64 65 66 67 68 69
## [39] 70 73 75 76 78 79 83 87 91 92 93 100 101 103 107 108 109 110 111
## [58] 115 116 122 124 126 127 128 130 134 135 137 139 141 142 143 144 149 150
##
## $Fold1.Rep2
## [1] 1 6 7 8 9 10 12 14 15 16 17 20 21 22 24 25 27 31 37
## [20] 38 40 42 46 47 48 51 52 53 55 57 59 61 63 64 65 67 72 74
## [39] 76 77 78 79 80 81 82 83 89 90 91 93 101 104 106 107 108 110 113
## [58] 114 115 119 121 122 124 129 130 132 133 135 136 138 139 140 143 144 150
##
## $Fold2.Rep2
## [1] 2 3 4 5 11 13 18 19 23 26 28 29 30 32 33 34 35 36 39
## [20] 41 43 44 45 49 50 54 56 58 60 62 66 68 69 70 71 73 75 84
## [39] 85 86 87 88 92 94 95 96 97 98 99 100 102 103 105 109 111 112 116
## [58] 117 118 120 123 125 126 127 128 131 134 137 141 142 145 146 147 148 149
7.4 时间序列抽样
简单随机抽样的时间序列可能不是最好的方法重新取样时间系列数据,将采用新的方法(滚动预测技术)
createTimeSlices(y, initialWindow, horizon = 1, fixedWindow = TRUE,skip = 0)
initialWindow: 最初的连续值的数量在每一个训练集样本
horizon:连续值在测试集样本的数量
fixedWindow:一个逻辑:如果FALSE,训练集总是从第一个样本训练集数据分割大小会有所不同。
createTimeSlices(1:9, initialWindow=5, horizon=1, fixedWindow = FALSE)
## $train
## $train$Training5
## [1] 1 2 3 4 5
##
## $train$Training6
## [1] 1 2 3 4 5 6
##
## $train$Training7
## [1] 1 2 3 4 5 6 7
##
## $train$Training8
## [1] 1 2 3 4 5 6 7 8
##
##
## $test
## $test$Testing5
## [1] 6
##
## $test$Testing6
## [1] 7
##
## $test$Testing7
## [1] 8
##
## $test$Testing8
## [1] 9
createTimeSlices(1:9, initialWindow=5, horizon=1, fixedWindow = TRUE)
## $train
## $train$Training5
## [1] 1 2 3 4 5
##
## $train$Training6
## [1] 2 3 4 5 6
##
## $train$Training7
## [1] 3 4 5 6 7
##
## $train$Training8
## [1] 4 5 6 7 8
##
##
## $test
## $test$Testing5
## [1] 6
##
## $test$Testing6
## [1] 7
##
## $test$Testing7
## [1] 8
##
## $test$Testing8
## [1] 9
createTimeSlices(1:9, initialWindow=5, horizon=3, fixedWindow = TRUE)
## $train
## $train$Training5
## [1] 1 2 3 4 5
##
## $train$Training6
## [1] 2 3 4 5 6
##
##
## $test
## $test$Testing5
## [1] 6 7 8
##
## $test$Testing6
## [1] 7 8 9
createTimeSlices(1:9, initialWindow=5, horizon=3, fixedWindow = FALSE)
## $train
## $train$Training5
## [1] 1 2 3 4 5
##
## $train$Training6
## [1] 1 2 3 4 5 6
##
##
## $test
## $test$Testing5
## [1] 6 7 8
##
## $test$Testing6
## [1] 7 8 9
createTimeSlices(1:15, 5, 3)
## $train
## $train$Training05
## [1] 1 2 3 4 5
##
## $train$Training06
## [1] 2 3 4 5 6
##
## $train$Training07
## [1] 3 4 5 6 7
##
## $train$Training08
## [1] 4 5 6 7 8
##
## $train$Training09
## [1] 5 6 7 8 9
##
## $train$Training10
## [1] 6 7 8 9 10
##
## $train$Training11
## [1] 7 8 9 10 11
##
## $train$Training12
## [1] 8 9 10 11 12
##
##
## $test
## $test$Testing05
## [1] 6 7 8
##
## $test$Testing06
## [1] 7 8 9
##
## $test$Testing07
## [1] 8 9 10
##
## $test$Testing08
## [1] 9 10 11
##
## $test$Testing09
## [1] 10 11 12
##
## $test$Testing10
## [1] 11 12 13
##
## $test$Testing11
## [1] 12 13 14
##
## $test$Testing12
## [1] 13 14 15
createTimeSlices(1:15, 5, 3, skip = 2)
## $train
## $train$Training05
## [1] 1 2 3 4 5
##
## $train$Training08
## [1] 4 5 6 7 8
##
## $train$Training11
## [1] 7 8 9 10 11
##
##
## $test
## $test$Testing05
## [1] 6 7 8
##
## $test$Testing08
## [1] 9 10 11
##
## $test$Testing11
## [1] 12 13 14
createTimeSlices(1:15, 5, 3, skip = 3)
## $train
## $train$Training5
## [1] 1 2 3 4 5
##
## $train$Training9
## [1] 5 6 7 8 9
##
##
## $test
## $test$Testing5
## [1] 6 7 8
##
## $test$Testing9
## [1] 10 11 12
sessionInfo()
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Mojave 10.14.5
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
##
## locale:
## [1] zh_CN.UTF-8/zh_CN.UTF-8/zh_CN.UTF-8/C/zh_CN.UTF-8/zh_CN.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] caret_6.0-86 ggplot2_3.3.2 lattice_0.20-41
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.1.0 xfun_0.17 purrr_0.3.4
## [4] reshape2_1.4.4 splines_4.0.2 colorspace_1.4-1
## [7] vctrs_0.3.2 generics_0.0.2 fastICA_1.2-2
## [10] htmltools_0.5.0 stats4_4.0.2 yaml_2.2.1
## [13] survival_3.1-12 prodlim_2019.11.13 rlang_0.4.7
## [16] ModelMetrics_1.2.2.2 pillar_1.4.6 glue_1.4.1
## [19] withr_2.2.0 foreach_1.5.0 lifecycle_0.2.0
## [22] plyr_1.8.6 lava_1.6.7 stringr_1.4.0
## [25] timeDate_3043.102 munsell_0.5.0 blogdown_0.20
## [28] gtable_0.3.0 recipes_0.1.13 codetools_0.2-16
## [31] evaluate_0.14 knitr_1.29 class_7.3-17
## [34] Rcpp_1.0.5 scales_1.1.1 ipred_0.9-9
## [37] RANN_2.6.1 digest_0.6.25 stringi_1.4.6
## [40] bookdown_0.20 dplyr_1.0.1 grid_4.0.2
## [43] tools_4.0.2 magrittr_1.5 tibble_3.0.3
## [46] crayon_1.3.4 pkgconfig_2.0.3 ellipsis_0.3.1
## [49] MASS_7.3-51.6 Matrix_1.2-18 data.table_1.13.0
## [52] pROC_1.16.2 lubridate_1.7.9 gower_0.2.2
## [55] rmarkdown_2.3 iterators_1.0.12 R6_2.4.1
## [58] rpart_4.1-15 nnet_7.3-14 nlme_3.1-148
## [61] compiler_4.0.2