这是刚刚探索出来的一个小技巧,在这里记录一下!
对于个别变量的类型转换,例如从其他类型转化为因子变量,base
包中的transform()
函数或者dplyr
包中的mutate()
函数就可以快速完成:
library(tidyverse)
dta <- mtcars
# transform函数
dta %>%
transform(cyl = factor(cyl),
hp = factor(hp)) %>%
as_tibble()
# mutate函数
dta %>%
mutate(cyl = factor(cyl),
hp = factor(hp)) %>%
as_tibble()
可以看出两个函数在管道操作符中的使用方式还是比较相似的,都是将所有需要转换的变量依次写入即可。
但是,当需要转换类型的变量比较多时,这种挨个写入变量名的方式就很不适用了。这里就需要使用dplyr
包中的辅助函数across()
了。
across()
函数功能之一就是选择(select)指定变量名或符合约束条件的变量名,然后对这些变量进行函数运算,语法结构如下:
across(.cols = everything(), .fns = NULL, ..., .names = NULL)
上面.cols
就是选择出的变量,.fns
是应用于这些变量的函数。先列举几个常与它连用的辅助函数:
-
everyyhing()
:选择所有变量; -
starts_with()
:选择变量名以特定字符开始的变量; -
ends_with()
:选择变量名以特定字符结束的变量名。
上面的这些函数都来自于dplyr
包,这里先不做详细介绍,后面会有推文总结dplyr
中所有的辅助函数。另外关于dplyr
包中“选择(select)”的含义前面推文已有介绍(dplyr | 数据导入和预处理的常用函数)。
为了批量地将一个数据框中所有的整型变量都转换为因子,第一步是要选择出所有整型变量。
首先想到判断整型变量的函数应该是is.integer()
,但是在实操中发现,数据框的整型变量大多是以double(双精度)类型存在的,使用is.integer
不会选择出任何变量,也就达不到目的;而由于double类型也包括小数,所以使用is.double
会选择出多余的变量,同样达不到目的。对比结果如下:
dta %>%
mutate(across(where(is.integer), factor)) %>%
as_tibble()
dta %>%
mutate(across(where(is.double), factor)) %>%
as_tibble()
# 输出结果
> dta %>%
+ mutate(across(where(is.integer), factor)) %>%
+ as_tibble()
# A tibble: 32 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
7 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
8 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
9 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
10 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
# ... with 22 more rows
> dta %>%
+ mutate(across(where(is.double), factor)) %>%
+ as_tibble()
# A tibble: 32 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct> <fct>
1 21 6 160 110 3.9 2.62 16.46 0 1 4 4
2 21 6 160 110 3.9 2.875 17.02 0 1 4 4
3 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
4 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
5 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2
6 18.1 6 225 105 2.76 3.46 20.22 1 0 3 1
7 14.3 8 360 245 3.21 3.57 15.84 0 0 3 4
8 24.4 4 146.7 62 3.69 3.19 20 1 0 4 2
9 22.8 4 140.8 95 3.92 3.15 22.9 1 0 4 2
10 19.2 6 167.6 123 3.92 3.44 18.3 1 0 4 4
# ... with 22 more rows
可以看出,使用is.integer
没有任何变量被转化为factor类型,说明across()
中没有被添加任何变量名;而使用is.double
所有的变量都会被转化为factor类型。
由于上面两个函数都达不到目标,可以考虑从整数的特点出发,即整数除以1后的余数为0。R语言中的取余函数为%%
,基于此,可以自定义一个“选择”函数:
function(x) all(x %% 1 == 0)
all()
函数来自基础包base
,如果函数内的判断条件成立会返回TRUE,否则返回FALSE。
把自定义函数应用到across()
中:
dta %>%
mutate(across(function(col) all(col %% 1==0), factor)) %>%
as_tibble()
# 输出结果
> dta %>%
+ mutate(across(function(col) all(col %% 1==0), factor)) %>%
+ as_tibble()
# A tibble: 32 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<dbl> <fct> <dbl> <fct> <dbl> <dbl> <dbl> <fct> <fct> <fct> <fct>
1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
7 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
8 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
9 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
10 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
# ... with 22 more rows
可以看出,数据框中所有的整型变量都已经被转化为factor类型了,而非整型变量依然是原本的double类型,也就达到了批量转换变量类型的目的了。如果有其他类似的需求,对自定义函数进行对应的修改就可以了。