在dplyr中过滤字符串列上的多个值

105

我有一个包含字符数据的data.frame。 我希望从同一列中筛选出多个选项,有没有什么简单的方法可以做到这一点呢?

示例: data.frame名称为dat

days      name
88        Lynn
11        Tom
2         Chris
5         Lisa
22        Kyla
1         Tom
222       Lynn
2         Lynn

例如,我想要过滤掉TomLynn

当我执行以下操作时:

target <- c("Tom", "Lynn")
filt <- filter(dat, name == target)

我遇到了这个错误:

longer object length is not a multiple of shorter object length
7个回答

262

你需要使用%in%代替==

library(dplyr)
target <- c("Tom", "Lynn")
filter(dat, name %in% target)  # equivalently, dat %>% filter(name %in% target)

生成

  days name
1   88 Lynn
2   11  Tom
3    1  Tom
4  222 Lynn
5    2 Lynn

为了理解原因,请考虑这里发生的事情:

dat$name == target
# [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE

基本上,我们将长度为两个的target向量重复四次,以匹配dat$name的长度。换句话说,我们正在执行:

 Lynn == Tom
  Tom == Lynn
Chris == Tom
 Lisa == Lynn
 ... continue repeating Tom and Lynn until end of data frame
在这种情况下,我们不会因为我怀疑您的数据框实际上具有不允许循环使用的不同行数而出现错误,但您提供的示例却具有8行(可以进行循环使用)。如果示例具有奇数行,则我将像您一样收到相同的错误。但即使循环使用起作用,这显然也不是您想要的。基本上,语句dat $ name == target等同于说:

对于每个等于“Tom”的奇数值或等于“Lynn”的偶数值返回TRUE

恰好,在您的示例数据帧中,最后一个值为偶数且等于“Lynn”,因此以上的值为TRUE

相比之下,dat $ name%in%target表示:

对于dat $ name中的每个值,请检查其是否存在于target中。

非常不同。这是结果:

[1]  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE

请注意,您的问题与 dplyr 无关,只是 == 的误用。


1
谢谢你的解释,Brodie!非常感谢,我是一名临床医生,正在努力学习R语言! - Tom O
1
@BrodieG,你能否使用模式而不是完整字符串来创建目标? - user9440895
2
不要使用%in%,但是你可以使用grepl("T[oi]m|lynne?", name)并在那里使用任何模式。 - BrodieG
1
@user9440895,请查看我使用stringr答案 - rubengavidia0x
这个语句最好是:“基本上,我们将两个长度的目标向量重复四次,以匹配dat$name的长度。” 有些令人困惑,但我认为这完全错误。并不是有回收之类的操作。在底层,%in% 运算符只是一个匹配操作。 - IRTFM
可以使用%in%来过滤不在向量中的所有字符串(!%in%)吗? - undefined

15

可以使用dplyr程序包来实现,该程序包在CRAN上可用。实现这一点的简单方法如下:

  1. 安装 dplyr 程序包。
  2. 运行以下代码。
library(dplyr) 

df<- select(filter(dat,name=='tom'| name=='Lynn'), c('days','name))

解释:

所以,一旦我们下载了dplyr,我们可以使用这个包中的两个不同函数来创建一个新的数据框:

filter:第一个参数是数据框,第二个参数是我们想要提取子集的条件。结果是整个数据框,只有我们想要的行。

select:第一个参数是数据框,第二个参数是我们想要从中选择的列的名称。我们不必使用names()函数,甚至不必使用引号。我们只需将列名列出为对象即可。


14

使用 base 包:

df <- data.frame(days = c(88, 11, 2, 5, 22, 1, 222, 2), name = c("Lynn", "Tom", "Chris", "Lisa", "Kyla", "Tom", "Lynn", "Lynn"))

# Three lines
target <- c("Tom", "Lynn")
index <- df$name %in% target
df[index, ]

# One line
df[df$name %in% c("Tom", "Lynn"), ] 

输出:

  days name
1   88 Lynn
2   11  Tom
6    1  Tom
7  222 Lynn
8    2 Lynn

使用sqldf

library(sqldf)
# Two alternatives:
sqldf('SELECT *
      FROM df 
      WHERE name = "Tom" OR name = "Lynn"')
sqldf('SELECT *
      FROM df 
      WHERE name IN ("Tom", "Lynn")')

2

请写下这个例子:

library (dplyr)

target <- YourData%>% filter (YourColum %in% c("variable1","variable2"))

使用您的数据的示例

target <- df%>% filter (names %in% c("Tom","Lynn"))

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

1
如果您的字符串列中有长字符串作为值,您可以使用stringr包中的这个强大方法。这是filter( %in% )和基本R无法做到的。
library(dplyr)
library(stringr)

sentences_tb = as_tibble(sentences) %>%
                 mutate(row_number())
sentences_tb
# A tibble: 720 x 2
   value                                       `row_number()`
   <chr>                                                <int>
 1 The birch canoe slid on the smooth planks.               1
 2 Glue the sheet to the dark blue background.              2
 3 Its easy to tell the depth of a well.                   3
 4 These days a chicken leg is a rare dish.                 4
 5 Rice is often served in round bowls.                     5
 6 The juice of lemons makes fine punch.                    6
 7 The box was thrown beside the parked truck.              7
 8 The hogs were fed chopped corn and garbage.              8
 9 Four hours of steady work faced us.                      9
10 Large size in stockings is hard to sell.                10
# ... with 710 more rows                

matching_letters <- c(
  "canoe","dark","often","juice","hogs","hours","size"
)
matching_letters <- str_c(matching_letters, collapse = "|")
matching_letters
[1] "canoe|dark|often|juice|hogs|hours|size"

letters_found <- str_subset(sentences_tb$value,matching_letters)
letters_found_tb = as_tibble(letters_found)
inner_join(sentences_tb,letters_found_tb)

# A tibble: 16 x 2
   value                                          `row_number()`
   <chr>                                                   <int>
 1 The birch canoe slid on the smooth planks.                  1
 2 Glue the sheet to the dark blue background.                 2
 3 Rice is often served in round bowls.                        5
 4 The juice of lemons makes fine punch.                       6
 5 The hogs were fed chopped corn and garbage.                 8
 6 Four hours of steady work faced us.                         9
 7 Large size in stockings is hard to sell.                   10
 8 Note closely the size of the gas tank.                     33
 9 The bark of the pine tree was shiny and dark.             111
10 Both brothers wear the same size.                         253
11 The dark pot hung in the front closet.                    261
12 Grape juice and water mix well.                           383
13 The wall phone rang loud and often.                       454
14 The bright lanterns were gay on the dark lawn.            476
15 The pleasant hours fly by much too soon.                  516
16 A six comes up more often than a ten.                     609

这有点啰嗦,但如果您有长字符串并想要筛选包含特定单词的行所在位置,它非常方便和强大。

与已接受的答案相比:

> target <- c("canoe","dark","often","juice","hogs","hours","size")
> filter(sentences_tb, value %in% target)
# A tibble: 0 x 2
# ... with 2 variables: value <chr>, row_number() <int>

> df<- select(filter(sentences_tb,value=='canoe'| value=='dark'), c('value','row_number()'))
> df
# A tibble: 0 x 2
# ... with 2 variables: value <chr>, row_number() <int>

> target <- c("canoe","dark","often","juice","hogs","hours","size")
> index <- sentences_tb$value %in% target
> sentences_tb[index, ]
# A tibble: 0 x 2
# ... with 2 variables: value <chr>, row_number() <int>

你需要编写所有的句子才能得到所需的结果。


1
 by_type_year_tag_filtered <- by_type_year_tag %>%
      dplyr:: filter(tag_name %in% c("dplyr", "ggplot2"))

2
尽管这段代码可能提供了问题的解决方案,但强烈建议您提供有关为什么和/或如何回答问题的其他上下文信息。仅有代码的答案通常在长期内变得无用,因为未来的观众遇到类似问题时无法理解解决方案背后的推理过程。 - palaѕн

0
另一种选择可能是使用`slice`和`which`来获取要过滤的值的索引。以下是一些可重复的代码:
library(dplyr)
df %>%
  slice(which(name %in% c("Tom", "Lynn")))
#>   days name
#> 1   88 Lynn
#> 2   11  Tom
#> 3    1  Tom
#> 4  222 Lynn
#> 5    2 Lynn

使用reprex v2.0.2于2023年5月5日创建


所使用的数据:

df = read.table(text = "days      name
88        Lynn
11        Tom
2         Chris
5         Lisa
22        Kyla
1         Tom
222       Lynn
2         Lynn", header = TRUE)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接