如何使用 dplyr 独立过滤每一列的行

How to filter rows for every column independently using dplyr

我有以下问题:


library(tidyverse)
df <- tibble::tribble(
  ~gene, ~colB, ~colC,
  "a",   1,  2,
  "b",   2,  3,
  "c",   3,  4,
  "d",   1,  1
)

df
#> # A tibble: 4 x 3
#>    gene  colB  colC
#>   <chr> <dbl> <dbl>
#> 1     a     1     2
#> 2     b     2     3
#> 3     c     3     4
#> 4     d     1     1

我想做的是过滤掉 gene 列之后的每一列 对于大于或等于 2 (>=2) 的值。结果是:

gene, colB, colC
a   NA   2
b   2    3
c   3    4

我怎样才能做到这一点?

基因后面的列数实际上不止2列。

一个解决方案:从宽格式转换为长格式,这样您就可以只过滤一列,然后在最后根据需要转换回宽格式。请注意,这将丢弃没有值满足条件的基因。

library(tidyverse)
df %>% 
gather(name, value, -gene) %>% 
  filter(value >= 2) %>% 
  spread(name, value)

# A tibble: 3 x 3
   gene  colB  colC
* <chr> <dbl> <dbl>
1     a    NA     2
2     b     2     3
3     c     3     4

即将推出的 dplyr 0.6(如果您愿意,现在可以从 GitHub 安装)具有 filter_at,可用于过滤任何值大于或等于 2 的行,然后 na_if 可以通过 mutate_at 类似地应用,所以

df %>% 
    filter_at(vars(-gene), any_vars(. >= 2)) %>% 
    mutate_at(vars(-gene), funs(na_if(., . < 2)))
#> # A tibble: 3 x 3
#>    gene  colB  colC
#>   <chr> <dbl> <dbl>
#> 1     a    NA     2
#> 2     b     2     3
#> 3     c     3     4

或类似地,

df %>% 
    mutate_at(vars(-gene), funs(na_if(., . < 2))) %>% 
    filter_at(vars(-gene), any_vars(!is.na(.)))

可以翻译为与 dplyr 0.5 一起使用:

df %>% 
    mutate_at(vars(-gene), funs(na_if(., . < 2))) %>% 
    filter(rowSums(is.na(.)) < (ncol(.) - 1))

全部return一样。

我们可以使用data.table

library(data.table)
setDT(df)[df[, Reduce(`|`, lapply(.SD, `>=`, 2)), .SDcols = colB:colC]
   ][, (2:3) := lapply(.SD, function(x) replace(x, x < 2, NA)), .SDcols = colB:colC][]
#   gene colB colC
#1:    a   NA    2
#2:    b    2    3
#3:    c    3    4

或者用melt/dcast

dcast(melt(setDT(df), id.var = 'gene')[value>=2], gene ~variable)
#   gene colB colC
#1:    a   NA    2
#2:    b    2    3
#3:    c    3    4