根据dplyr :: select兼容的类/类型选择列
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了根据dplyr :: select兼容的类/类型选择列相关的知识,希望对你有一定的参考价值。
实际问题
如何定义一个select帮助器,它根据类/类型选择列,并且与dplyr
的体系结构兼容?
尽职调查
我看了https://cran.r-project.org/web/packages/dplyr/vignettes/introduction.html和dplyr::select_helpers
的帮助,但没有找到任何允许我根据类/类型选择的东西
例
带来一些变化WRT类/类型:
dat <- mtcars
dat <- dat %>% mutate(
mpg = as.character(mpg),
wt = as.factor(wt),
vs = as.character(vs)
)
简而言之,我想让它成为R中所有可能的类/类型(及其组合)的通用方法:
dat[ , sapply(dat, is.character)]
# mpg wt vs
# 1 21 2.62 0
# 2 21 2.875 0
# 3 22.8 2.32 1
# 4 21.4 3.215 1
基于Subset variables in data frame based on column type,我可以这样做:
select_on_class <- function(.data, cls = "numeric") {
dat[ , names(.data)[sapply(.data,
function(vec, clss) class(vec) %in% clss, clss = cls)]]
}
dat %>% select_on_class(c("character", "factor"))
# mpg wt vs
# 1 21 2.62 0
# 2 21 2.875 0
# 3 22.8 2.32 1
# 4 21.4 3.215 1
但我希望能够在调用dplyr::select
时使用它,所以我尝试了这个:
has_class <- function(.data, cls = "numeric") {
nms <- names(.data)[sapply(.data,
function(vec, clss) class(vec) %in% clss, clss = cls)]
sapply(nms, as.name)
}
dat %>% has_class(c("character", "factor"))
# $mpg
# mpg
#
# $wt
# wt
#
# $vs
# vs
问题是sapply(nms, as.name)
返回list
并且与select
的内部结构不太好(我还不完全理解,BTW):
dat %>% select(has_class(c("character", "factor")))
# Error: All select() inputs must resolve to integer column positions.
# The following do not:
# * has_class("character")
dat %>% select_(has_class(c("character", "factor")))
# Error in UseMethod("as.lazy") :
# no applicable method for 'as.lazy' applied to an object of class "list"
编辑
基于使用select_if
的答案,我试图概括并陷入困境:
has_class <- function(.data, cls) {
sapply(.data, function(vec, clss) class(vec) %in% clss, clss = cls)
}
dat %>% has_class(c("character", "factor"))
# mpg cyl disp hp drat wt qsec vs am gear carb
# TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE
dat %>% select_if(has_class, c("character", "factor"))
# Error in vapply(tbl, p, logical(1), ...) : values must be length 1,
# but FUN(X[[1]]) result is length 32
AFAIU,.predicate
函数只需要返回一个逻辑向量(has_class
),我可以通过.predicate
(我做过)将其他参数传递给...
函数。那我在哪里还会出错?
我认为dplyr::select_if()
可能就是你想要的。例如
dat <- mtcars %>%
mutate(mpg = as.character(mpg),
wt = as.character(wt),
vs = as.character(vs)
) %>%
select_if(is.character)
如果不是list,我们可以从自定义函数返回一个字符向量,然后我们可以使用one_of
:
has_class_v1 <- function(.data, cls = "numeric") {
names(.data)[sapply(.data,
function(vec, clss) class(vec) %in% clss, clss = cls)]
}
has_class_v1(dat, "character")
# [1] "mpg" "wt" "vs"
# use one_of
dat %>%
select(one_of(has_class_v1(.,"character"))) %>%
head
# mpg wt vs
# 1 21 2.62 0
# 2 21 2.875 0
# 3 22.8 2.32 1
# 4 21.4 3.215 1
# 5 18.7 3.44 0
# 6 18.1 3.46 1
在利用dplyr
的同时,在我看来实现这一目标的最简化和最普遍的方法是使用dplyr::select_if
但是以比@wjchulme建议的方式更直接的方式(虽然这是一个很好的技巧):
dat %>%
select_if(sapply(., class) %in% c("numeric", "character"))
等等,如果需要更多的课程。我希望这有帮助。
以上是关于根据dplyr :: select兼容的类/类型选择列的主要内容,如果未能解决你的问题,请参考以下文章
更新 dplyr,dplyr::select_vars 中的错误
max(.) 中的错误:使用 dplyr dbplyr 和 bigrquery 时参数的“类型”(列表)无效
R:错误:在 dplyr 中使用 unnest 时长度不兼容