有没有办法产生类似于mutate_at或mutate_if的collect_at或collect_if函数

时间:2018-11-21 15:26:01

标签: r dplyr

我认为标题相当简单。 但仅提供一些数据和示例:

test <- tibble(
ID1 = letters,
ID2 = LETTERS,
A1 = runif(26),
B1 = runif(26),
A2 = runif(26),
B2 = runif(26)
)

是否有一种方法可以使用simple命令仅收集数字列,例如:

test %>% gather_if(is.numeric, 'key', 'value')

?它将产生与以下相同的输出:

> test %>% gather('key', 'value', -ID1, -ID2)
# A tibble: 104 x 4
   ID1   ID2   key    value
   <chr> <chr> <chr>  <dbl>
 1 a     A     A1    0.558 
 2 b     B     A1    0.0614
 3 c     C     A1    0.999 
 4 d     D     A1    0.854 
 5 e     E     A1    0.463 
 6 f     F     A1    0.875 
 7 g     G     A1    0.796 
 8 h     H     A1    0.484 
 9 i     I     A1    0.336 
10 j     J     A1    0.191 
# ... with 94 more rows

查看收集功能:

> gather
function (data, key = "key", value = "value", ..., na.rm = FALSE, 
    convert = FALSE, factor_key = FALSE) 
{
    UseMethod("gather")
}
<bytecode: 0x000000001b71ff18>
<environment: namespace:tidyr>

修改它似乎并不直接(至少对于半新颖的R用户而言不是)。

编辑:

我在dplyr中选择的词汇可能不完全准确。但是我认为MWE很好地解释了我要使用的功能类型。

编辑2:

使用bschneidr的答案,可以通过以下方式完成此问题的临时版本。

gather_if <- function(data, fun, key, value, ..., na.rm = FALSE, convert = 
FALSE, factor_key = FALSE){
    data %>%
        gather(!!key, !!value, select_if(., fun) %>% colnames(), ...,
               na.rm = FALSE, convert = FALSE, factor_key = FALSE)
}

哪个给:

> test %>% gather_if(is.numeric, 'key', 'value')
# A tibble: 104 x 4
   ID1   ID2   key    value
   <chr> <chr> <chr>  <dbl>
 1 a     A     A1    0.558 
 2 b     B     A1    0.0614
 3 c     C     A1    0.999 
 4 d     D     A1    0.854 
 5 e     E     A1    0.463 
 6 f     F     A1    0.875 
 7 g     G     A1    0.796 
 8 h     H     A1    0.484 
 9 i     I     A1    0.336 
10 j     J     A1    0.191 
# ... with 94 more rows

3 个答案:

答案 0 :(得分:2)

我认为gather_if函数正在为tidyr工作(请参见tidyr的Github存储库上的this pull request)。

目前,我认为最简单的方法是在对select_if的调用中使用dplyr的gather函数。

test %>% 
    gather('key', 'value',
           colnames(select_if(., is.numeric)))

答案 1 :(得分:1)

一种实现方法是negate()数字条件并提取名称。看起来确实很麻烦,但是在这里,

library(tidyverse)

gather(test, key, value, -c(test %>% select_if(negate(is.numeric)) %>% names()))

给出,

# A tibble: 104 x 4
   ID1   ID2   key    value
   <chr> <chr> <chr>  <dbl>
 1 a     A     A1    0.624 
 2 b     B     A1    0.0740
 3 c     C     A1    0.790 
 4 d     D     A1    0.312 
 5 e     E     A1    0.323 
 6 f     F     A1    0.826 
 7 g     G     A1    0.0533
 8 h     H     A1    0.0828
 9 i     I     A1    0.979 
10 j     J     A1    0.453 
# ... with 94 more rows

答案 2 :(得分:1)

如果您想这样做:

gather_if <- function(data, FUN, key = "key", value = "value", na.rm = FALSE, convert = FALSE, factor_key = FALSE) {
    data %>% {gather(., key = key, value = value , names(.)[sapply(., FUN = FUN)], na.rm = na.rm, convert = convert, factor_key = factor_key )}
} 

调用您的新酷功能:

test %>% gather_if(is.numeric, 'key', 'value')

结果:

# A tibble: 104 x 4
#   ID1   ID2   key   value
#   <chr> <chr> <chr> <dbl>
# 1 a     A     A1    0.693
# 2 b     B     A1    0.356
# 3 c     C     A1    0.650
# 4 d     D     A1    0.358
# 5 e     E     A1    0.650
# 6 f     F     A1    0.461
# 7 g     G     A1    0.222
# 8 h     H     A1    0.993
# 9 i     I     A1    0.679
#10 j     J     A1    0.331
# ... with 94 more rows