如何在dplyr中select_if,其中逻辑条件被否定

ast*_*nes 7 select r function dplyr

我想从数据框中选择所有数字列,然后选择所有非数字列.一个显而易见的方法是: -

mtcars %>%
    select_if(is.numeric) %>%
    head()
Run Code Online (Sandbox Code Playgroud)

这完全符合我的预期.

mtcars %>%
    select_if(!is.numeric) %>%
    head()
Run Code Online (Sandbox Code Playgroud)

这不会,并产生错误消息错误!is.numeric:无效的参数类型

看另一种做同样事情的方法: -

mtcars %>%
    select_if(sapply(., is.numeric)) %>%
    head()
Run Code Online (Sandbox Code Playgroud)

效果很好,但是

mtcars %>%
    select_if(sapply(., !is.numeric)) %>%
    head()
Run Code Online (Sandbox Code Playgroud)

失败并显示相同的错误消息.(purrr :: keep表现完全相同).

在这两种情况下使用-删除不需要的列也会失败,与上面的is.numeric版本的错误相同,并且此错误消息为sapply版本错误:无法将整数向量转换为函数.

is.numeric的帮助页面说

is.numeric是一个内部泛型原语函数:您可以编写处理特定类对象的方法,请参阅InternalMethods....如果类的基类型是double或integer,并且值可以合理地视为数值,则is.numeric的方法应该只返回true(例如,对它们的算术是有意义的,并且应该通过基类型进行比较) .

帮助页面!说

对于!,与x相同长度的逻辑或原始向量(对于原始x):名称,dims和dimnames是从x复制的,如果没有强制,则复制所有其他属性(包括类).

dplyr管道中查看有用的问题Negation !,%>%我可以看到为什么这不起作用的一些原因,但是没有一个解决方案表明它有效.

mtcars %>%
    select_if(not(is.numeric())) %>%
    head()
Run Code Online (Sandbox Code Playgroud)

给出合理的错误 is.numeric()中的错误:传递给'is.numeric'的0个参数需要1.

mtcars %>%
    select_if(not(is.numeric(.))) %>%
    head()
Run Code Online (Sandbox Code Playgroud)

失败并出现此错误: - tbl_if_vars中的错误(.tbl,.predicate,caller_env(),. include_group_vars = TRUE):length(.p)== length(tibble_vars)不为TRUE.

这种行为绝对违反了最不惊讶的原则.这对我来说并不重要,但它表明我没有理解一些更基本的观点.

有什么想法吗?

Aur*_*èle 11

否定谓词函数可以使用专用Negate()purrr::negate()函数(而不是!操作符,否定向量)来完成:

library(dplyr)

mtcars %>% 
  mutate(foo = "bar") %>% 
  select_if(Negate(is.numeric)) %>% 
  head()

#   foo
# 1 bar
# 2 bar
# 3 bar
# 4 bar
# 5 bar
# 6 bar
Run Code Online (Sandbox Code Playgroud)

或(purrr::negate()(小写)行为略有不同,请参阅相应的帮助页面):

library(purrr)
library(dplyr)

mtcars %>% 
  mutate(foo = "bar") %>% 
  select_if(negate(is.numeric)) %>% 
  head()

#   foo
# 1 bar
# 2 bar
# 3 bar
# 4 bar
# 5 bar
# 6 bar
Run Code Online (Sandbox Code Playgroud)


Dan*_*ann 5

您可以定义自己的"非数字"功能,然后使用它

is_not_num <- function(x) !is.numeric(x)

mtcars %>%
select_if(is_not_num) %>%
head()
Run Code Online (Sandbox Code Playgroud)