我想通过一组用户定义的列和值来过滤数据框。
示例数据:test
col1 col2 col3
1 1 a 4
2 2 b 5
3 3 c 6
4 3 c 7
如果用户指定使用c("col1", "col2")
来过滤值c(3, "c")
,我希望返回的结果是最后两行。
我尝试了以下内容:
test[test[c("col1", "col2")]==c(3,"c"),]
然而,它给出了以下结果:
col1 col2 col3
3 3 c 6
NA NA NA NA
知道为什么最后一行都是NA吗? 我该如何解决这个问题?
答案 0 :(得分:4)
我们需要正确获取rowindex。它可以是vector
logical
或numeric
索引。在比较中(最好使用list
而不是c
因为我们不想混合类),我们得到一个逻辑matrix
,需要将其简化为向量。一个选项是rowSums
并检查每行的总和是否等于2,即用于比较的列数和行的子集
test[rowSums(test[c("col1", "col2")] == list(3, 'c'))==2,]
# col1 col2 col3
#3 3 c 6
#4 3 c 7
现在,我们使用c
和list
test[c("col1", "col2")]==c(3,"c")
# col1 col2
#1 FALSE FALSE
#2 FALSE FALSE
#3 TRUE FALSE
#4 FALSE TRUE
这里,它通过一个接一个地循环元素来比较元素,即'col1',1与3比较,然后2与'c',然后再循环矢量,即3与3再次下一个3与'c'。它与下一列的方式相同。
test[c("col1", "col2")]== list(3,"c")
# col1 col2
#1 FALSE FALSE
#2 FALSE FALSE
#3 TRUE TRUE #note the change
#4 TRUE TRUE
虽然,在这里,它将第一列元素与list
的第一个元素进行比较,即复制或回收list
元素,然后将第二列与第二个list
元素进行比较< / p>
请注意,有8个元素,即每列4个元素。因此,在第一种情况下有2个TRUE元素,在第二种情况下有4个TRUE,并且有8个元素,但是我们只有4行,所以当逻辑矩阵的第二列没有行时,它会创建TRUE值的NA行
test[test[c("col1", "col2")]==c(3,"c"),]
# col1 col2 col3
#3 3 c 6
#NA NA <NA> NA
同样,每列中有2个TRUE,再次创建NA行数的两倍
test[test[c("col1", "col2")]==list(3,"c"),]
# col1 col2 col3
#3 3 c 6
#4 3 c 7
#NA NA <NA> NA
#NA.1 NA <NA> NA
假设我们还比较了第3列,那么将会有一个额外的NA行
test[test==list(3,"c", 5),]
# col1 col2 col3
#3 3 c 6
#4 3 c 7
#NA NA <NA> NA
#NA.1 NA <NA> NA
#NA.2 NA <NA> NA
答案 1 :(得分:0)
这是我的dplyr
解决方案:
library(dplyr)
test %>%
rowwise() %>%
mutate(con = if_else(col1 %in% 3 & col2 %in% "c",TRUE, FALSE)) %>%
filter(con == TRUE) %>%
select(-con) %>%
ungroup
答案 2 :(得分:0)
另一个{tidyeval <{1}}版本
dplyr
答案 3 :(得分:0)
这是为了将akrun answer扩展到更真实的示例,其中搜索列中的数据可能包含NA
。在这种情况下,最终输出中的“NA”行会变得混乱并且可能会混淆下游分析。在此示例中,我使用num
值列出了col2
和NA
列。只有NA
中的col2
才有效,因为它在搜索中使用。此问题的根源是使用NA
进行操作的任何内容NA
(例如NA == 1 = NA
),is.na
除外
mydf <- data.frame(num = c(1:3, NA, 5, 6), col1 = c('a', 'b', 'a', 'b', 'c', 'd'), col2 = c('A', 'b', 'A', 'B', NA, 'D'), col3 = as.character(letters)[1:6])
getrows = mydf[c("col2", "col1")] == list("A", "a") # Mixing up column orders for fun
getrows = rowSums(getrows) == 2
getrows
mydf[getrows, ] # This gives undesired NA rows
# Use which to get exact row number
which(getrows)
mydf[which(getrows),]
比较下面的输出:
> mydf <- data.frame(num = c(1:3, NA, 5, 6), col1 = c('a', 'b', 'a', 'b', 'c', 'd'), col2 = c('A', 'b', 'A', 'B', NA, 'D'), col3 = as.character(letters)[1:6])
> getrows = mydf[c("col2", "col1")] == list("A", "a") # Mixing up column orders for fun
> getrows = rowSums(getrows) == 2
> getrows
[1] TRUE FALSE TRUE FALSE NA FALSE
> mydf[getrows, ] # This gives undesired NA rows
num col1 col2 col3
1 1 a A a
3 3 a A c
NA NA <NA> <NA> <NA>
> # Use which to get exact row number
> which(getrows)
[1] 1 3
> mydf[which(getrows),]
num col1 col2 col3
1 1 a A a
3 3 a A c