在前面的推文中我们介绍了数据预处理的重要性以及演示了caret
包中的数据预处理方法:
一定要先看上两篇推文,因为一些方法解释和原理都在前面解释过
今天列举常见的数据预处理方法,使用recipes
包。这个包是tidymodels
的一部分,专门用于数据预处理,是非常重要的一个部分,并且也包含部分特征选择的函数。
本文将会介绍recipes
的基本用法以及一些常用的数据预处理方法实现。
recipes
的使用其实很简单,但是由于数据预处理步骤非常多,难以记住,所以我把一些常用的recipes
的预处理函数列在这里,方便大家选择。
主要包括以下几个部分内容:
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.1 ✔ purrr 1.0.1
## ✔ tibble 3.2.1 ✔ dplyr 1.1.1
## ✔ tidyr 1.3.0 ✔ stringr 1.5.0
## ✔ readr 2.1.4 ✔ forcats 1.0.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(tidymodels)
## ── Attaching packages ────────────────────────────────────── tidymodels 1.0.0 ──
## ✔ broom 1.0.3 ✔ rsample 1.1.1
## ✔ dials 1.1.0 ✔ tune 1.0.1
## ✔ infer 1.0.4 ✔ workflows 1.1.2
## ✔ modeldata 1.1.0 ✔ workflowsets 1.0.0
## ✔ parsnip 1.0.3 ✔ yardstick 1.1.0
## ✔ recipes 1.0.4
## ── Conflicts ───────────────────────────────────────── tidymodels_conflicts() ──
## ✖ scales::discard() masks purrr::discard()
## ✖ dplyr::filter() masks stats::filter()
## ✖ recipes::fixed() masks stringr::fixed()
## ✖ dplyr::lag() masks stats::lag()
## ✖ yardstick::spec() masks readr::spec()
## ✖ recipes::step() masks stats::step()
## • Use suppressPackageStartupMessages() to eliminate package startup messages
tidymodels_prefer()
使用之前用过的segmentationOriginal
数据:
library(AppliedPredictiveModeling)
library(caret)
## Loading required package: lattice
data("segmentationOriginal")
segData <- subset(segmentationOriginal, Case == "Train")
cellID <- segData$Cell
class <- segData$Class
case <- segData$Case
#segData <- segData[ , -(1:3)]
statusColNum <- grep("Status", names(segData))
statusColNum
## [1] 5 7 12 13 14 15 17 19 23 24 25 29 30 31 33 35 37 39 41
## [20] 43 46 47 49 51 54 55 58 59 62 63 66 67 71 72 73 75 76 77
## [39] 79 81 83 85 87 89 91 95 96 97 100 101 106 107 108 109 113 114 115
## [58] 117
segData <- segData[ , -statusColNum]
segData <- segData[,-(1:2)]
dim(segData) # 使用的演示数据
## [1] 1009 59
1个函数同时完成中心化和标准化:
step_normalize()
也有分开版本:
# 选择数据预处理步骤
# 首先第一步是建立recipe
rec <- recipe(Class ~ ., data = segData)
# 然后一步一步地添加你想要的预处理步骤
preproc <- rec %>%
step_center(XCentroid,YCentroid) %>% # 中心化
step_scale(XCentroid,YCentroid) %>% # 标准化
prep()
preproc
## Recipe
##
## Inputs:
##
## role #variables
## outcome 1
## predictor 58
##
## Training data contained 1009 data points and no missing data.
##
## Operations:
##
## Centering for XCentroid, YCentroid [trained]
## Scaling for XCentroid, YCentroid [trained]
注意上面数据预处理步骤的写法,第一步是建立recipe
,然后是选择预处理步骤,在recipes
中,所有的数据预处理步骤都是以step_xxx
这种形式出现的;
然后是预处理应用于哪些变量,可以直接写变量名字,和dplyr
中一模一样的方法,所以也支持tidyselect
包的各种用法,比如contains()/starts_with()/ends_with()/matches()/num_range()
等,这种写法。
除此之外,还支持recipes
的一些简便操作。由于数据预处理一般是作用于预测变量,有的是数值型,有的是分类变量,所以tidymodels
开发了一些好用的函数,用于快速选择变量。主要是以下几个:
# 官网这部分更新很快,可以到官网查看最新的,这里只是一些常用的
all_numeric()
all_integer()
all_double()
all_nominal()
all_ordered()
all_unordered()
all_factor()
all_string()
all_date()
all_datetime()
all_numeric_predictors()
all_nominal_predictors()
all_predictors()
all_outcomes()
看名字就知道,是用来选择不同类型的变量的,使用方法也很简单:
recipe(HHV ~ ., data = biomass) %>%
step_center(all_numeric_predictors()) # 把中心化应用于 "所有的数值型预测变量"
是不是很方便呢?
如果你想把数据预处理步骤应用于数据,记得最后一定要加上prep()
,然后使用bake()
函数执行预处理步骤:
segdata_scaled <- bake(preproc, new_data = NULL)
glimpse(segdata_scaled)
## Rows: 1,009
## Columns: 59
## $ AngleCh1 <dbl> 133.75204, 106.64639, 69.15032, 109.41643, 104…
## $ AreaCh1 <int> 819, 431, 298, 256, 258, 358, 158, 315, 246, 2…
## $ AvgIntenCh1 <dbl> 31.92327, 28.03883, 19.45614, 18.82857, 17.570…
## $ AvgIntenCh2 <dbl> 205.878517, 115.315534, 101.294737, 125.938776…
## $ AvgIntenCh3 <dbl> 69.91688, 63.94175, 28.21754, 13.60000, 22.461…
## $ AvgIntenCh4 <dbl> 164.15345, 106.69660, 31.02807, 46.80000, 71.2…
## $ ConvexHullAreaRatioCh1 <dbl> 1.263158, 1.053310, 1.202625, 1.081871, 1.0757…
## $ ConvexHullPerimRatioCh1 <dbl> 0.7970801, 0.9354750, 0.8658291, 0.9204595, 0.…
## $ DiffIntenDensityCh1 <dbl> 31.87500, 32.48771, 26.73228, 28.02004, 27.876…
## $ DiffIntenDensityCh3 <dbl> 43.12228, 35.98577, 22.91732, 14.87082, 16.119…
## $ DiffIntenDensityCh4 <dbl> 79.30842, 51.35705, 26.39370, 32.69710, 36.185…
## $ EntropyIntenCh1 <dbl> 6.087592, 5.883557, 5.420065, 5.383272, 5.1842…
## $ EntropyIntenCh3 <dbl> 6.642761, 6.683000, 5.436732, 4.151183, 5.4862…
## $ EntropyIntenCh4 <dbl> 7.880155, 7.144601, 5.778329, 6.194035, 6.6246…
## $ EqCircDiamCh1 <dbl> 32.30558, 23.44892, 19.50279, 18.08245, 18.156…
## $ EqEllipseLWRCh1 <dbl> 1.558394, 1.375386, 3.391220, 1.378748, 1.6160…
## $ EqEllipseOblateVolCh1 <dbl> 2232.9055, 802.1945, 724.7143, 368.3097, 403.6…
## $ EqEllipseProlateVolCh1 <dbl> 1432.8246, 583.2504, 213.7031, 267.1334, 249.7…
## $ EqSphereAreaCh1 <dbl> 3278.7256, 1727.4104, 1194.9320, 1027.2222, 10…
## $ EqSphereVolCh1 <dbl> 17653.525, 6750.985, 3884.084, 3095.782, 3133.…
## $ FiberAlign2Ch3 <dbl> 0.48793541, 0.30052198, 0.22042390, 0.36423599…
## $ FiberAlign2Ch4 <dbl> 0.35237425, 0.52231582, 0.73325044, 0.48086857…
## $ FiberLengthCh1 <dbl> 64.28230, 21.14115, 43.14112, 22.29743, 26.528…
## $ FiberWidthCh1 <dbl> 13.167079, 21.141150, 7.404412, 12.057876, 10.…
## $ IntenCoocASMCh3 <dbl> 0.028051061, 0.006862315, 0.030962071, 0.10816…
## $ IntenCoocASMCh4 <dbl> 0.012594975, 0.006141691, 0.011033195, 0.00995…
## $ IntenCoocContrastCh3 <dbl> 8.2279529, 14.4460738, 7.2994574, 6.1605846, 9…
## $ IntenCoocContrastCh4 <dbl> 6.984046, 16.700843, 13.390884, 10.590685, 10.…
## $ IntenCoocEntropyCh3 <dbl> 6.822138, 7.580100, 6.312641, 5.044067, 6.9574…
## $ IntenCoocEntropyCh4 <dbl> 7.098988, 7.671478, 7.197026, 7.126900, 7.1447…
## $ IntenCoocMaxCh3 <dbl> 0.15321477, 0.02835052, 0.16279070, 0.31531532…
## $ IntenCoocMaxCh4 <dbl> 0.07387141, 0.02319588, 0.07751938, 0.05855856…
## $ KurtIntenCh1 <dbl> -0.24876907, -0.29348463, 0.62585612, -0.36469…
## $ KurtIntenCh3 <dbl> -0.3307839, 1.0512813, 0.1277406, 1.0833329, -…
## $ KurtIntenCh4 <dbl> -0.2652638, 0.1506140, -0.3472936, -0.6262704,…
## $ LengthCh1 <dbl> 47.21855, 28.14303, 37.85957, 23.05547, 26.319…
## $ NeighborAvgDistCh1 <dbl> 174.4442, 158.4774, 206.3344, 263.6345, 231.15…
## $ NeighborMinDistCh1 <dbl> 30.11114, 34.94477, 33.08030, 38.43038, 29.848…
## $ NeighborVarDistCh1 <dbl> 81.38063, 90.43768, 116.89276, 88.50411, 103.4…
## $ PerimCh1 <dbl> 154.89876, 84.56460, 101.09107, 68.71062, 73.4…
## $ ShapeBFRCh1 <dbl> 0.5397584, 0.7243116, 0.5891625, 0.6347914, 0.…
## $ ShapeLWRCh1 <dbl> 1.468181, 1.328408, 2.826854, 1.313937, 1.4903…
## $ ShapeP2ACh1 <dbl> 2.255810, 1.272193, 2.545840, 1.397364, 1.5886…
## $ SkewIntenCh1 <dbl> 0.39870467, 0.47248709, 0.88167138, 0.54673722…
## $ SkewIntenCh3 <dbl> 0.6197308, 0.9713788, 0.9998928, 1.4323632, 0.…
## $ SkewIntenCh4 <dbl> 0.52726313, 0.32470650, 0.60443988, 0.70380065…
## $ SpotFiberCountCh3 <int> 4, 2, 4, 0, 1, 1, 4, 2, 2, 2, 6, 4, 0, 1, 4, 2…
## $ SpotFiberCountCh4 <int> 11, 6, 7, 5, 4, 5, 4, 2, 5, 1, 10, 3, 2, 7, 6,…
## $ TotalIntenCh1 <int> 24964, 11552, 5545, 4613, 4340, 14461, 4743, 8…
## $ TotalIntenCh2 <int> 160997, 47510, 28869, 30855, 30719, 74259, 154…
## $ TotalIntenCh3 <int> 54675, 26344, 8042, 3332, 5548, 14474, 6265, 5…
## $ TotalIntenCh4 <int> 128368, 43959, 8843, 11466, 17588, 23099, 1753…
## $ VarIntenCh1 <dbl> 18.80923, 17.29564, 13.81897, 13.92294, 12.324…
## $ VarIntenCh3 <dbl> 56.71535, 37.67105, 30.00564, 18.64303, 17.747…
## $ VarIntenCh4 <dbl> 118.38814, 49.47052, 24.74954, 40.33175, 41.92…
## $ WidthCh1 <dbl> 32.16126, 21.18553, 13.39283, 17.54686, 17.660…
## $ XCentroid <dbl> -0.367797851, 0.752354868, 1.585288942, -0.396…
## $ YCentroid <dbl> 1.5684377, 0.6831217, 1.0838436, 2.9476668, 0.…
## $ Class <fct> PS, WS, PS, WS, PS, PS, PS, WS, WS, WS, WS, PS…
通过这个例子我们也可以发现recipes
的基本用法,这个包主要就是用于数据预处理,所有的数据预处理步骤都是step_xxx
这种形式,第一步都是以recipe()
函数开头,建立你的“菜谱”,里面写上你的formula
和data
,然后通过管道符不断连接新的数据预处理方法,最后以prep()
结尾,接着使用bake()
函数,执行这些数据预处理步骤。
就像做饭一样,一步一步来,这也是这个包为什么叫recipes
的原因!
通过psych
包查看:
psych::skew(segData$AreaCh1) # 偏度
## [1] 3.525107
psych::kurtosi(segData$AreaCh1) # 峰度
## [1] 19.04179
画图查看:
ggplot(segData, aes(x = AreaCh1))+
geom_histogram(bins = 10)
plot of chunk unnamed-chunk-9
以下是recipes
中一些可以改善数据偏度的预处理函数:
step_inverse()
step_log()
step_logit()
step_invlogit()
step_sqrt()
step_YeoJohnson()
演示下Boxcox变换:
preproc <- rec %>%
step_center(XCentroid,YCentroid) %>%
step_scale(XCentroid,YCentroid) %>%
step_BoxCox(AreaCh1) %>%
prep()
preproc
## Recipe
##
## Inputs:
##
## role #variables
## outcome 1
## predictor 58
##
## Training data contained 1009 data points and no missing data.
##
## Operations:
##
## Centering for XCentroid, YCentroid [trained]
## Scaling for XCentroid, YCentroid [trained]
## Box-Cox transformation on AreaCh1 [trained]
执行预处理步骤,再次画图查看:
segdata_boxcox <- bake(preproc, new_data = NULL)
ggplot(segdata_boxcox, aes(x = AreaCh1))+
geom_histogram(bins = 10)
plot of chunk unnamed-chunk-12
step_interact()
data(biomass, package = "modeldata")
biomass_tr <- biomass[biomass$dataset == "Training", ]
biomass_te <- biomass[biomass$dataset == "Testing", ]
# 建立菜谱
rec <- recipe(
HHV ~ carbon + hydrogen + oxygen + nitrogen + sulfur,
data = biomass_tr
)
# 添加食材
ss_trans <- rec %>%
step_center(carbon, hydrogen) %>%
step_scale(carbon, hydrogen) %>%
step_spatialsign(carbon, hydrogen)
# 准备好了,可以下锅了
ss_obj <- prep(ss_trans, training = biomass_tr)
# 下锅制作
transformed_te <- bake(ss_obj, biomass_te)
# 画图查看之前的
plot(biomass_te$carbon, biomass_te$hydrogen)
plot of chunk unnamed-chunk-14
# 画图查看之后的
plot(transformed_te$carbon, transformed_te$hydrogen)
plot of chunk unnamed-chunk-14
# 获取数据预处理步骤
tidy(ss_trans, number = 3)
## # A tibble: 2 × 2
## terms id
## <chr> <chr>
## 1 carbon spatialsign_BPYzj
## 2 hydrogen spatialsign_BPYzj
tidy(ss_obj, number = 3)
## # A tibble: 2 × 2
## terms id
## <chr> <chr>
## 1 carbon spatialsign_BPYzj
## 2 hydrogen spatialsign_BPYzj
常用的方法如下,看名字就知道是哪些方法,如果你看到这些名字不认识,说明你可能还不适合看这个教程,先去学习下一些降维的基础知识。
step_pca()
step_ica()
step_nnmf()
step_pls()
recipes
中缺失值插补的方法非常多,所有都是以step_impute_xxx
的形式出现,而且名字简单易懂,大家选择合适的即可!
step_impute_bag()
step_impute_knn()
step_impute_linear()
step_impute_lower()
step_impute_mean()
step_impute_median()
step_impute_mode()
step_impute_roll()
移除预测变量其实属于特征选择内容,这部分内容在caret
包的教程中有详细的介绍,大家可以搜索历史推文。
step_corr()
step_filter()
step_filter_missing()
step_lincomb()
step_zv()
step_nzv()
step_rm()
step_select()
比如创建哑变量等,还包括对因子型变量的常见处理,和forcats
包做的事情非常相似,大家可以参考我们的forcats
包系列推文:
step_dummy()
step_bin2factor()
step_factor2string()
step_string2factor()
step_num2factor()
step_other()
step_percentile()
step_unknown()
主要是对变量进行分箱操作。
step_cut()
step_discretize()
以上就是recipes
中常见的数据预处理步骤,它的用法很简单,语法非常统一,还是比较容易记住的,所以只演示了前几个,这里的每一个数据预处理步骤的具体细节以及产生的相应变化,我都在前几篇推文中详细解释过了,所以这里只是列出了一些函数名字,并没有进行具体的演示哦~
除此之外,还有一些数据预处理的函数我没有介绍,比如**样条变换(就是大家喜欢的立方样条、β样条等)**,感兴趣的可以自己了解下。
后面会继续为大家介绍mlr3
中的数据预处理方法。