【问题标题】:R dpylr select_if with multiple conditions [closed]具有多个条件的 R dplyr select_if [关闭]
【发布时间】:2016-09-20 11:28:19
【问题描述】:

我想按名称选择所有数值变量以及一些变量。我已经设法使用 select_if 来获取数字变量并选择按名称获取变量,但不能将两者组合成一个语句

x = data.table(c(1,2,3),c(10,11,12),c('a','b','c'),c('x','y','z'), c('l', 'm','n'))

我希望我的结果是:

V1 V2 V4 V5
1 10  x l
2 11  y m
3 12  z n

我试过了,但是不行

y = x %>%
select_if(is.numeric, V4, V5)

【问题讨论】:

  • str(x) 显示所有列都是字符。我认为这是错误的潜在原因?我也想知道你是否可以直接使用列名。
  • cbind 的目的是什么?只需使用data.table。使用cbind,所有内容都被强制转换为character 矩阵,因此每一列都是character。如果您将x 定义为data.table(c(1,2,3),c(10,11,12),c('a','b','c'),c('x','y','z'), c('l', 'm','n')),那么x %>% select_if(is.numeric) 有效(V4V5select_if 中的用途是什么?)
  • @nicola 是什么让你认为 OP 在他的包中犯了错误?据我所知,dtplyr 包含data.table。您的编辑与 IMO 的作者意图相冲突。
  • @Tensibai Ops,我不知道dtplyr,还以为OP打错了。
  • @nicola 没问题。

标签: r select dplyr


【解决方案1】:

如果我们有一个数据框,x:

x = data.frame(V1=c(1,2,3),V2=c(10,11,12),V3=c('a','b','c'),V4=c('x','y','z'),V5=c('l', 'm','n'), stringsAsFactors=FALSE)
##  V1 V2 V3 V4 V5
##1  1 10  a  x  l
##2  2 11  b  y  m
##3  3 12  c  z  n

其中V1V2 实际上是numeric 而其余列都不是因子,那么我们可以这样做:

library(dplyr)
y <- x %>% select_if(function(col) is.numeric(col) | 
                                   all(col == .$V4) | 
                                   all(col == .$V5))
##  V1 V2 V4 V5
##1  1 10  x  l
##2  2 11  y  m
##3  3 12  z  n

并不是说这是最好的做法,但它确实可以满足您的需求。这里的问题是select_if 期望它的函数返回一个对应于所有列的布尔向量。

另一种方法是使用select:

y <- x %>% select(which(sapply(.,class)=="numeric"),V4,V5)
##  V1 V2 V4 V5
##1  1 10  x  l
##2  2 11  y  m
##3  3 12  z  n

这可能更好。

【讨论】:

  • 这有一个讨厌的副作用。 all(col %in% .$V4) 不等于 col 实际上是 .$V4all(col == .$V4) 可能是更好的选择。
  • @AlexR:谢谢。我会做出改变。但是,我认为我对select_if 的整个回答有一个令人讨厌的副作用:-)
  • 使用select_at 是更好的选择吗?
  • 仅在最后一个选项上略短:x %>% select(c(which(sapply(., is.numeric)), "V4", "V5"))
  • @RafaelToledo: x %>% select_at(vars(names(.)[sapply(., is.numeric)], "V4", "V5"))
【解决方案2】:

map 的一个选项(来自purrr

library(purrr)
x %>%
     map2(names(x), ~.[is.numeric(.x)|.y != "V3"])  %>%
     Filter(length, .) %>% 
     bind_cols
 #     V1    V2    V4    V5
 #  <dbl> <dbl> <chr> <chr>
 #1     1    10     x     l
 #2     2    11     y     m
 #3     3    12     z     n

或如@RoyalTS 建议的那样

x %>% 
    imap( ~ .[is.numeric(.x)|.y != "V3"]) %>%
    keep(~length(.x) > 0) %>%
    bind_cols

由于数据集是data.table,子集data.table 的选项是

x[, sapply(x, is.numeric) | colnames(x) != "V3", with = FALSE]
#   V1 V2 V4 V5
#1:  1 10  x  l
#2:  2 11  y  m
#3:  3 12  z  n

数据

x <- data.table(c(1,2,3),c(10,11,12),c('a','b','c'),c('x','y','z'), 
              c('l', 'm','n')) 

注意:@nicola 提到了为什么不需要cbind。因此,我们没有描述已经提出的相同问题。

【讨论】:

  • @RonakShah 你是对的。我本可以使用colnames(x) %in% c("V4", "V5"),但我认为"V3" 会缩短
  • @RonakShah 是的,先生,您是对的。在这种情况下,%in% c("V4", "V5") 应该是要走的路。
  • 现在你可以用imap(~.[is.numeric(.x)|.y != "V3"])替换map2(names(x), ~.[is.numeric(.x)|.y != "V3"])
【解决方案3】:

使用data.frame函数:

x = data.frame(V1=c(1,2,3),V2=c(10,11,12),V3=c('a','b','c'),V4=c('x','y','z'),V5=c('l', 'm','n'))

然后x %&gt;% select_if(is.numeric) 工作。

【讨论】:

    猜你喜欢
    • 2019-01-30
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2019-10-10
    • 2019-02-09
    • 1970-01-01
    相关资源
    最近更新 更多