数据帧动态过滤

时间:2017-12-12 16:47:08

标签: r

我想通过一组用户定义的列和值来过滤数据框。

示例数据: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吗? 我该如何解决这个问题?

4 个答案:

答案 0 :(得分:4)

我们需要正确获取rowindex。它可以是vector logicalnumeric索引。在比较中(最好使用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

现在,我们使用clist

查看方法上的差异
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值列出了col2NA列。只有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