提问人:littleworth 提问时间:3/15/2018 更新时间:11/11/2022 访问量:15307
如何使用 dplyr 管道删除所有列均为零的行
How to remove rows where all columns are zero using dplyr pipe
问:
我有以下数据框:
dat <- structure(list(`A-XXX` = c(1.51653275922944, 0.077037240321129,
0), `fBM-XXX` = c(2.22875185527511, 0, 0), `P-XXX` = c(1.73356698481106,
0, 0), `vBM-XXX` = c(3.00397859609183, 0, 0)), .Names = c("A-XXX",
"fBM-XXX", "P-XXX", "vBM-XXX"), row.names = c("BATF::JUN_AHR",
"BATF::JUN_CCR9", "BATF::JUN_IL10"), class = "data.frame")
dat
#> A-XXX fBM-XXX P-XXX vBM-XXX
#> BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
#> BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
#> BATF::JUN_IL10 0.00000000 0.000000 0.000000 0.000000
我可以使用以下命令删除包含所有列零的行:
> dat <- dat[ rowSums(dat)!=0, ]
> dat
A-XXX fBM-XXX P-XXX vBM-XXX
BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
但是我怎样才能用 dplyr 的管道风格做到这一点呢?
答:
我们可以使用 from 根据逻辑向量获取行和数据集的总和reduce
purrr
filter
library(tidyverse)
dat %>%
reduce(`+`) %>%
{. != 0} %>%
filter(dat, .)
# A-XXX fBM-XXX P-XXX vBM-XXX
#1 1.51653276 2.228752 1.733567 3.003979
#2 0.07703724 0.000000 0.000000 0.000000
注意:在 中,row.names 被剥离。最好稍后创建新列或分配 row.names%>%
如果我们还需要行名,请尽早创建一个行名列,然后使用它来更改末尾的行名
dat %>%
rownames_to_column('rn') %>%
filter(rowSums(.[-1]) != 0) %>%
`row.names<-`(., .[['rn']]) %>% select(-rn)
# A-XXX fBM-XXX P-XXX vBM-XXX
#BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
#BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
评论
dat
filter(dat,.)
filter
dat
下面是一个 dplyr 选项:
library(dplyr)
filter_all(dat, any_vars(. != 0))
# A-XXX fBM-XXX P-XXX vBM-XXX
#1 1.51653276 2.228752 1.733567 3.003979
#2 0.07703724 0.000000 0.000000 0.000000
在这里,我们利用这样的逻辑:如果任何变量不等于零,我们将保留它。这与删除所有变量都等于零的行相同。
关于 row.names:
library(tidyverse)
dat %>% rownames_to_column() %>% filter_at(vars(-rowname), any_vars(. != 0))
# rowname A-XXX fBM-XXX P-XXX vBM-XXX
#1 BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
#2 BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
评论
if_any
across()
这是第三个选项,用于生成所有行是否为零的索引。绝对不如 ,但使用 !purrr::pmap
filter_at
pmap
dat <- structure(list(`A-XXX` = c(1.51653275922944, 0.077037240321129,
0), `fBM-XXX` = c(2.22875185527511, 0, 0), `P-XXX` = c(1.73356698481106,
0, 0), `vBM-XXX` = c(3.00397859609183, 0, 0)), .Names = c("A-XXX",
"fBM-XXX", "P-XXX", "vBM-XXX"), row.names = c("BATF::JUN_AHR",
"BATF::JUN_CCR9", "BATF::JUN_IL10"), class = "data.frame")
library(tidyverse)
dat %>%
rownames_to_column() %>%
bind_cols(all_zero = pmap_lgl(., function(rowname, ...) all(list(...) == 0))) %>%
filter(all_zero == FALSE) %>%
`rownames<-`(.$rowname) %>%
select(-rowname, -all_zero)
#> A-XXX fBM-XXX P-XXX vBM-XXX
#> BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
#> BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
由 reprex 软件包 (v0.2.0) 于 2018-03-14 创建。
这是使用 dplyr 的逐行运算的另一个选项(定义三个示例列,计算按行总和):col1,col2,col3
library(tidyverse)
df <- df %>%
rowwise() %>%
filter(sum(c(col1,col2,col3)) != 0)
或者,如果您有大量变量(列)可供选择,您也可以通过以下方式使用 tidyverse 选择语法:
df <- df %>%
rowwise() %>%
filter(sum(c_across(col1:col3)) != 0)
有关详细信息,请参阅:https://dplyr.tidyverse.org/articles/rowwise.html
更新 2022-11-11
使用最新的 tidyverse 软件包,.现在更新的解决方案是:across() in filter() is deprecated
data %>% filter(if_all(everything(.), ~. != 0))
旧解决方案(已终止)
通过@mgrund补充答案, DPLYR 1.0.0 的较短替代方案是:
# Option A:
data %>% filter(across(everything(.)) != 0))
# Option B:
data %>% filter(across(everything(.), ~. != 0))
说明:
检查每个tidy_select变量,该变量表示每一列。在选项 A 中,如果每列不为零,则检查每一列,这加起来就是每列中一整行零。在选项 B 中,对每一列都应用公式 (~),用于检查当前列是否为零。across()
everything()
编辑:
由于已经按行检查,因此您不需要.这与 或 不同。filter
rowwise()
select
mutate
重要提示:
在选项 A 中,关键是要写 ,
而不是 !across(everything(.)) != 0
across(everything(.) != 0))
原因:
需要一个 tidyselect 变量(这里),而不是布尔值(这将是across
everything()
everything(.) != 0)
)
评论
filter()
..1
logical
..1
across(everything() != 0)
rowwise
您可以使用新的 .我定制了一个在文档中找到的示例if_any()
if_any()
library(dplyr)
library(tibble)
dat <- structure(list(`A-XXX` = c(1.51653275922944, 0.077037240321129,
0), `fBM-XXX` = c(2.22875185527511, 0, 0), `P-XXX` = c(1.73356698481106,
0, 0), `vBM-XXX` = c(3.00397859609183, 0, 0)), .Names = c("A-XXX",
"fBM-XXX", "P-XXX", "vBM-XXX"), row.names = c("BATF::JUN_AHR",
"BATF::JUN_CCR9", "BATF::JUN_IL10"), class = "data.frame")
dat
#> A-XXX fBM-XXX P-XXX vBM-XXX
#> BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
#> BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
#> BATF::JUN_IL10 0.00000000 0.000000 0.000000 0.000000
dat %>%
rownames_to_column("ID") %>%
filter(if_any(!matches("ID"), ~ . != 0)) %>%
column_to_rownames("ID")
#> A-XXX fBM-XXX P-XXX vBM-XXX
#> BATF::JUN_AHR 1.51653276 2.228752 1.733567 3.003979
#> BATF::JUN_CCR9 0.07703724 0.000000 0.000000 0.000000
创建于 2021-04-12 由 reprex 软件包 (v1.0.0)
评论