使用dplyr过滤包含特定字符串的行

Gia*_*uca 159 r filter dplyr

我必须使用包含字符串的行作为标准来过滤数据帧RTB.我正在使用dplyr.

d.del <- df %.%
  group_by(TrackingPixel) %.%
  summarise(MonthDelivery = as.integer(sum(Revenue))) %.%
  arrange(desc(MonthDelivery))
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用该函数filter,dplyr但我不知道如何告诉它检查字符串的内容.

特别是我想检查列中的内容TrackingPixel.如果字符串包含RTB我想从结果中删除行的标签.

ale*_*emm 221

这个问题的答案已经由@latemail在上面的评论中发布了.您可以使用正则表达式作为第二个和后续参数,filter如下所示:

dplyr::filter(df, !grepl("RTB",TrackingPixel))
Run Code Online (Sandbox Code Playgroud)

由于您尚未提供原始数据,我将使用mtcars数据集添加玩具示例.想象一下,您只对马自达或丰田生产的汽车感兴趣.

mtcars$type <- rownames(mtcars)
dplyr::filter(mtcars, grepl('Toyota|Mazda', type))

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb           type
1 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4      Mazda RX4
2 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4  Mazda RX4 Wag
3 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1 Toyota Corolla
4 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1  Toyota Corona
Run Code Online (Sandbox Code Playgroud)

如果你想反过来做,即不包括丰田和马自达汽车,filter命令看起来像这样:

dplyr::filter(mtcars, !grepl('Toyota|Mazda', type))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,当对象是`tbl_sql`时,这不起作用,因为`grepl`不会转换为sql. (13认同)
  • 确保使用dplyr包中的过滤器功能,而不是stats包 (3认同)
  • @MySchizoBuddy:如果列名称包含空格,则可以使用反引号选择变量.修改上面的例子:`mtcars $ \`我的类型\`< - rownames(mtcars)`然后``mtcars%>%filter(grepl('丰田|马自达',\`我的类型\`)) (2认同)

Kei*_*iku 124

它是可以使用str_detect的的stringr包中包含tidyverse包.str_detect返回TrueFalse关于指定的向量是否包含某些特定字符串.可以使用此布尔值进行过滤.有关包的详细信息,请参见stringr简介stringr.

library(tidyverse)
# ? Attaching packages ???????????????????? tidyverse 1.2.1 ?
# ? ggplot2 2.2.1     ? purrr   0.2.4
# ? tibble  1.4.2     ? dplyr   0.7.4
# ? tidyr   0.7.2     ? stringr 1.2.0
# ? readr   1.1.1     ? forcats 0.3.0
# ? Conflicts ????????????????????? tidyverse_conflicts() ?
# ? dplyr::filter() masks stats::filter()
# ? dplyr::lag()    masks stats::lag()

mtcars$type <- rownames(mtcars)
mtcars %>%
  filter(str_detect(type, 'Toyota|Mazda'))
# mpg cyl  disp  hp drat    wt  qsec vs am gear carb           type
# 1 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4      Mazda RX4
# 2 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4  Mazda RX4 Wag
# 3 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1 Toyota Corolla
# 4 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1  Toyota Corona
Run Code Online (Sandbox Code Playgroud)

Stringr的好处

我们应该使用而stringr::str_detect()不是base::grepl().这是因为有以下原因.

  • stringr包提供的函数以前缀开头str_,这使代码更易于阅读.
  • stringrpackage 函数的第一个参数总是data.frame(或value),然后是参数.(谢谢Paolo)
object <- "stringr"
# The functions with the same prefix `str_`.
# The first argument is an object.
stringr::str_count(object) # -> 7
stringr::str_sub(object, 1, 3) # -> "str"
stringr::str_detect(object, "str") # -> TRUE
stringr::str_replace(object, "str", "") # -> "ingr"
# The function names without common points.
# The position of the argument of the object also does not match.
base::nchar(object) # -> 7
base::substr(object, 1, 3) # -> "str"
base::grepl("str", object) # -> TRUE
base::sub("str", "", object) # -> "ingr"
Run Code Online (Sandbox Code Playgroud)

基准

基准测试的结果如下.对于大型数据帧,str_detect速度更快.

library(rbenchmark)
library(tidyverse)

# The data. Data expo 09. ASA Statistics Computing and Graphics 
# http://stat-computing.org/dataexpo/2009/the-data.html
df <- read_csv("Downloads/2008.csv")
print(dim(df))
# [1] 7009728      29

benchmark(
  "str_detect" = {df %>% filter(str_detect(Dest, 'MCO|BWI'))},
  "grepl" = {df %>% filter(grepl('MCO|BWI', Dest))},
  replications = 10,
  columns = c("test", "replications", "elapsed", "relative", "user.self", "sys.self"))
# test replications elapsed relative user.self sys.self
# 2      grepl           10  16.480    1.513    16.195    0.248
# 1 str_detect           10  10.891    1.000     9.594    1.281
Run Code Online (Sandbox Code Playgroud)

  • @Tjebo我添加了基准测试的结果。请确认。 (3认同)
  • @CameronNemo `stringr` 包提供的函数以前缀 str_ 开头,这使得代码更易于阅读。在最近的现代 R 代码中,建议使用 stringr。 (2认同)
  • 我认为这是一个非常个人的偏爱,并且我同意@CameronNemo的观点,即“ base R”和“ stringr”一样好。如果您向我们提供一些“硬性事实”(例如基准测试),并且不仅说明“推荐”(谁推荐),我们将不胜感激。谢谢 (2认同)
  • 另一个原因是tidyverse框架的一致性:函数的第一个参数始终是data.frame(或值),然后是参数。 (2认同)

Net*_*tle 14

这个答案与其他答案类似,但使用首选stringr::str_detect和dplyr rownames_to_column.

library(tidyverse)

mtcars %>% 
  rownames_to_column("type") %>% 
  filter(stringr::str_detect(type, 'Toyota|Mazda') )

#>             type  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
#> 1      Mazda RX4 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
#> 2  Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
#> 3 Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
#> 4  Toyota Corona 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Run Code Online (Sandbox Code Playgroud)

reprex包(v0.2.0)创建于2018-06-26.


Tje*_*ebo 8

编辑包括较新的across()语法

这是另一个tidyverse解决方案,使用filter(across())或 之前filter_at。优点是您可以轻松扩展到多列

下面还有一个解决方案,filter_all用于在任何列中查找字符串,diamonds例如,查找字符串“V”

library(tidyverse)
Run Code Online (Sandbox Code Playgroud)

只有一列的字符串

# for only one column... extendable to more than one creating a column list in `across` or `vars`!
mtcars %>% 
  rownames_to_column("type") %>% 
  filter(across(type, ~ !grepl('Toyota|Mazda', .))) %>%
  head()
#>                type  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
#> 1        Datsun 710 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
#> 2    Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
#> 3 Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
#> 4           Valiant 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
#> 5        Duster 360 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
#> 6         Merc 240D 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Run Code Online (Sandbox Code Playgroud)

现在被取代的语法是:

mtcars %>% 
  rownames_to_column("type") %>% 
  filter_at(.vars= vars(type), all_vars(!grepl('Toyota|Mazda',.))) 
Run Code Online (Sandbox Code Playgroud)

所有列中的字符串:

# for only one column... extendable to more than one creating a column list in `across` or `vars`!
mtcars %>% 
  rownames_to_column("type") %>% 
  filter(across(type, ~ !grepl('Toyota|Mazda', .))) %>%
  head()
#>                type  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
#> 1        Datsun 710 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
#> 2    Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
#> 3 Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
#> 4           Valiant 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
#> 5        Duster 360 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
#> 6         Merc 240D 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Run Code Online (Sandbox Code Playgroud)

现在被取代的语法是:

diamonds %>% 
  filter_all(all_vars(!grepl('V', .))) %>%
  head
Run Code Online (Sandbox Code Playgroud)

我试图为以下内容找到一个替代方案,但我没有立即想出一个好的解决方案:

    #get all rows where any column contains 'V'
    diamonds %>%
    filter_all(any_vars(grepl('V',.))) %>%
      head
    #> # A tibble: 6 x 10
    #>   carat cut       color clarity depth table price     x     y     z
    #>   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
    #> 1 0.23  Good      E     VS1      56.9    65   327  4.05  4.07  2.31
    #> 2 0.290 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
    #> 3 0.24  Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
    #> 4 0.24  Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
    #> 5 0.26  Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
    #> 6 0.22  Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
Run Code Online (Sandbox Code Playgroud)

更新:感谢用户 Petr Kajzar在这个答案中,这里也是上述的一种方法:

diamonds %>%
   filter(rowSums(across(everything(), ~grepl("V", .x))) > 0)
Run Code Online (Sandbox Code Playgroud)

  • 你知道为什么 `diamonds %&gt;% filter(across(everything(), ~grepl('V', .)))` 返回一个空的 tibble 吗?我认为简单地删除“!”会返回任何列中带有 V 的所有行? (2认同)