我想删除总和为 0 的所有行,但前 2 列中有因子列。我想出了一个 dplyr 解决方案,创建一个中间 rowsum 列,过滤掉总和为 0 的行,然后删除该 rowsum 列。
我想找到一种方法来使其工作而无需创建不必要的 rowsum 列,两者都使用基本 R 和 dplyr/tidyverse 管道友好方法。肯定有一段简单的单行代码可以实现这一点吗?
library(tidyverse)
df <- data.frame(person = rep(c("Ed", "Sue"), 6),
id = paste0("plot",1:12),
a = c(2, 0, 0, 0, 0, 1, 0, 0, 4, 0, 0, 0),
b = c(0, 0, 6, 4, 0, 8, 1, 0, 0, 0, 1, 1),
c = c(4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8),
d = c(0, 0, 0, 3, 0, 1, 0, 0, 9, 0, 1, 5),
e = c(7, 0, 5, 0, 0, 1, 0, 0, 0, 0, 7, 0))
##create intermediate 'row.sum' column, filter rows that have all 0's, then remove row.sum column
df1 <- df %>%
dplyr::mutate(row.sum = a+b+c+d+e) %>%
dplyr::filter(row.sum != 0) %>%
dplyr::select(-row.sum)
#end result:
# person id a b c d e
#1 Ed plot1 2 0 4 0 7
#2 Ed plot3 0 6 0 0 5
#3 Sue plot4 0 4 0 3 0
#4 Sue plot6 1 8 0 1 1
#5 Ed plot7 0 1 0 0 0
#6 Ed plot9 4 0 0 9 0
#7 Ed plot11 0 1 3 1 7
#8 Sue plot12 0 1 8 5 0
Run Code Online (Sandbox Code Playgroud)
一个 dplyr 方法
您只能将 rowSums 应用于数字列,使用 dplyrsfilter()
和across()
,以及帮助程序where(is.numeric)
:
library(dplyr)
df%>%filter(rowSums(across(where(is.numeric)))!=0)
person id a b c d e
1 Ed plot1 2 0 4 0 7
2 Ed plot3 0 6 0 0 5
3 Sue plot4 0 4 0 3 0
4 Sue plot6 1 8 0 1 1
5 Ed plot7 0 1 0 0 0
6 Ed plot9 4 0 0 9 0
7 Ed plot11 0 1 3 1 7
8 Sue plot12 0 1 8 5 0
Run Code Online (Sandbox Code Playgroud)
rowSums()
如果您的数字列也有负值,则此方法(以及一些依赖于 的方法)可能会失败。在这种情况下,我们必须确保只保留至少包含any()
非零值的行。这可以通过修改来完成rowSums()
,包括在条件.x!=0
内across()
:
df%>%filter(rowSums(across(where(is.numeric), ~.x!=0))>0)
Run Code Online (Sandbox Code Playgroud)
或者使用逻辑运算符 and Reduce()/reduce()
,使用以下代码:
library(dplyr)
library(purrr)
df%>%filter(pmap_lgl(select(., where(is.numeric)), ~any(c(...)!=0)))
#or with purrr:reduce()#
df%>%filter(across(where(is.numeric), ~.x!=0)%>%reduce(`|`))
#or simply
df%>%filter(reduce(across(where(is.numeric), ~.x!=0), `|`))
Run Code Online (Sandbox Code Playgroud)
一个基本的R方法
您可以使用带有[
, with 的基本子集sapply(f, is.numeric)
来创建逻辑索引以仅选择数字列以提供给不等式运算符!=
,然后采用rowSums()
创建的最终逻辑矩阵的 并仅选择 rowSums > 0 的行:
df[rowSums(df[,sapply(df, is.numeric)]!=0)>0,]
Run Code Online (Sandbox Code Playgroud)
编辑
我们可以从对数字向量调用逻辑函数的强制转换中受益。as.logical()
将零评估为 FALSE,将任何非零数字评估为 TRUE。x|x
和嵌套的爆炸标志!(!)
也会这样做。这与将元素与零进行比较的其他解决方案一致,因此比rowSums
解决方案更一致。
一个例子:
vector<-c(0,1,2,-1)
identical(as.logical(vector), vector|vector, vector!=0, !(!vector))
[1] TRUE
Run Code Online (Sandbox Code Playgroud)
考虑到这一点,有一些巧妙的方法可以解决这个问题:
df%>%filter(reduce(across(where(is.numeric), as.logical), `|`))
#or simply
df%>%filter(reduce(across(where(is.numeric)), `|`))
#and with base R:
df[Reduce(`|`, df[sapply(df, is.numeric)]),]
Run Code Online (Sandbox Code Playgroud)
迄今为止最干净的,新的if_any()
:
df%>%filter(if_any(where(is.numeric)))
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
270 次 |
最近记录: |