如何 select 行比较具有相同值的多个列?
How to select rows comparing multiple columns with the same value?
假设我有以下数据和一个列名向量
dt <- data.table(id = letters[1:10], amount = 1:10, id2 = c(rep('a',5),rep('b',5)),test=rep('a',10))
cols <- c('id','id2','test')
我想要做的是 select 行,其中向量中的所有列都具有相同的特定值,例如
dt[id=='a' & id2=='a' & test == 'a']
但使用矢量 cols
。有办法吗?
注意: 我需要找到一种使用 data.table
或 base R
的方法,而无需在
等列之间进行比较
dt[id==id2 & id==test & id2==test]
使用 dplyr
和 purrr
,您可以:
dt %>%
filter(reduce(.x = across(all_of(cols), ~ . == "a"), .f = `&`))
id amount id2 test
1: a 1 a a
或使用 data.table
的相同想法:
dt[dt[, Reduce(`&`, lapply(.SD, function(x) x == "a")), .SDcols = cols]]
你可以求助于.SDcols
-
library(data.table)
dt[dt[, rowSums(.SD == 'a') == length(cols), .SDcols = cols]]
# id amount id2 test
#1: a 1 a a
这也可以写成-
dt[rowSums(dt[, ..cols] == 'a') == length(cols), ]
使用if_all
library(dplyr)
dt %>%
filter(if_all(all_of(cols), ~ . == 'a'))
id amount id2 test
1: a 1 a a
这是一个 data.table
友好的解决方案,它不寻找文字 "a"
:
此辅助函数仅采用其参数的 table
,如果不同元素的数量不是“1”,则采用 returns TRUE
。 (我测试 2L
因为我使用 useNA="always"
,它总是会附加一个 NA
计数,即使是 0。)
allsame <- function(x) do.call(mapply, c(list(FUN = function(...) length(table(unlist(list(...)), useNA = "always")) == 2L), x))
从这里开始,您可以在外部或内部使用它:
dt[allsame(dt[,..cols]),]
# id amount id2 test
# <char> <int> <char> <char>
# 1: a 1 a a
它实际上不是 data.table
特定的,它可以处理任何东西,只要它的参数是一个 data.frame
类对象,包含您需要比较的所有评论。
mtcars[1:3,10:11]
# gear carb
# Mazda RX4 4 4
# Mazda RX4 Wag 4 4
# Datsun 710 4 1
allsame(mtcars[1:3,10:11])
# [1] TRUE TRUE FALSE
另一个选项是使用连接:
dt[as.list(rep('a', length(cols))), on=cols]
假设我有以下数据和一个列名向量
dt <- data.table(id = letters[1:10], amount = 1:10, id2 = c(rep('a',5),rep('b',5)),test=rep('a',10))
cols <- c('id','id2','test')
我想要做的是 select 行,其中向量中的所有列都具有相同的特定值,例如
dt[id=='a' & id2=='a' & test == 'a']
但使用矢量 cols
。有办法吗?
注意: 我需要找到一种使用 data.table
或 base R
的方法,而无需在
dt[id==id2 & id==test & id2==test]
使用 dplyr
和 purrr
,您可以:
dt %>%
filter(reduce(.x = across(all_of(cols), ~ . == "a"), .f = `&`))
id amount id2 test
1: a 1 a a
或使用 data.table
的相同想法:
dt[dt[, Reduce(`&`, lapply(.SD, function(x) x == "a")), .SDcols = cols]]
你可以求助于.SDcols
-
library(data.table)
dt[dt[, rowSums(.SD == 'a') == length(cols), .SDcols = cols]]
# id amount id2 test
#1: a 1 a a
这也可以写成-
dt[rowSums(dt[, ..cols] == 'a') == length(cols), ]
使用if_all
library(dplyr)
dt %>%
filter(if_all(all_of(cols), ~ . == 'a'))
id amount id2 test
1: a 1 a a
这是一个 data.table
友好的解决方案,它不寻找文字 "a"
:
此辅助函数仅采用其参数的 table
,如果不同元素的数量不是“1”,则采用 returns TRUE
。 (我测试 2L
因为我使用 useNA="always"
,它总是会附加一个 NA
计数,即使是 0。)
allsame <- function(x) do.call(mapply, c(list(FUN = function(...) length(table(unlist(list(...)), useNA = "always")) == 2L), x))
从这里开始,您可以在外部或内部使用它:
dt[allsame(dt[,..cols]),]
# id amount id2 test
# <char> <int> <char> <char>
# 1: a 1 a a
它实际上不是 data.table
特定的,它可以处理任何东西,只要它的参数是一个 data.frame
类对象,包含您需要比较的所有评论。
mtcars[1:3,10:11]
# gear carb
# Mazda RX4 4 4
# Mazda RX4 Wag 4 4
# Datsun 710 4 1
allsame(mtcars[1:3,10:11])
# [1] TRUE TRUE FALSE
另一个选项是使用连接:
dt[as.list(rep('a', length(cols))), on=cols]