r - R - 从数据框中删除仅在数字列中包含零的行、基本 R 和管道友好方法?
问题描述
我想删除所有总和为 0 的行,但我在前 2 列中有因子列。我想出了一个 dplyr 解决方案,创建一个中间行和列,过滤掉总和为 0 的行,然后删除该行和列。
我想找到一种方法可以在不创建不必要的 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
解决方案
一个 dplyr 方法
您可以使用 dplyrsfilter()
和使用across()
helper仅将 rowSums 应用于数字列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
rowSums()
如果您的数字列也具有负值,则此方法(以及一些依赖于 的方法)可能会失败。在这种情况下,我们必须确保只保留至少包含any()
非零值的行。这可以通过修改rowSums()
以包含其中的条件来.x!=0
完成across()
:
df%>%filter(rowSums(across(where(is.numeric), ~.x!=0))>0)
或使用逻辑运算符 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), `|`))
基础 R 方法
您可以使用 base subsetting with [
, withsapply(f, is.numeric)
创建一个逻辑索引以仅选择数字列以提供给不等式运算符!=
,然后获取rowSums()
最终创建的逻辑矩阵的 并仅选择 rowSums > 0 的行:
df[rowSums(df[,sapply(df, is.numeric)]!=0)>0,]
编辑
我们可以从在数字向量上调用逻辑函数所带来的强制中受益。as.logical()
会将零评估为 FALSE,将任何非零数字评估为 TRUE。x|x
嵌套!(!)
的爆炸符号也会这样做。这与将元素与零进行比较的其他解决方案一致,因此比rowSums
解决方案更一致。
一个例子:
vector<-c(0,1,2,-1)
identical(as.logical(vector), vector|vector, vector!=0, !(!vector))
[1] TRUE
考虑到这一点,有一些巧妙的方法可以解决这个问题:
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)]),]
迄今为止最干净的,新的if_any()
:
df%>%filter(if_any(where(is.numeric)))
推荐阅读
- ruby-on-rails - RoR:测试重复用户失败
- android - react-native-vector-icons/羽毛图标不显示
- java - NFS(Netapp 服务器)-> Flink -> s3
- postgresql - 从 grafana 连接到 postgresql
- arrays - 如何在 Swift 中过滤对象以仅显示其值?
- javascript - 如何始终显示当前在 Canvas 对象上播放的音频对象的频率?
- java - 如何使用 Java 在 Selenium 中按键盘 ALT + I
- javascript - 在每个车轮事件上更改页面
- r - 在 R 中加载 csv 文件时出现无效的多字节字符串错误
- sql - 创建sql查询,将sybase数据库表中可用的数据批量生成csv文件