Lọc các hàng có chứa một chuỗi nhất định


188

Tôi phải lọc một khung dữ liệu bằng cách sử dụng làm tiêu chí cho các hàng chứa chuỗi RTB.

Tôi đang sử dụng dplyr.

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

Tôi biết tôi có thể sử dụng hàm filtertrong dplyrnhưng tôi không biết chính xác làm thế nào để nói với nó để kiểm tra nội dung của chuỗi.

Đặc biệt tôi muốn kiểm tra nội dung trong cột TrackingPixel. Nếu chuỗi chứa nhãn RTBtôi muốn xóa hàng khỏi kết quả.


27
Tôi chưa bao giờ sử dụng dplyr, nhưng nhìn vào sự giúp đỡ trong ?dplyr::filtertôi muốn đề xuất một cái gì đó như filter(df, !grepl("RTB",TrackingPixel))có thể?
thelHRail

1
Điều này thực sự gần với những gì tôi muốn đạt được. Vấn đề duy nhất là duy trì các chuỗi bao gồm nhãn RTBvà không hiển thị các chuỗi khác.
Gianluca

Tôi vừa đưa vào một chỉnh sửa lén lút, bây giờ đã đảo ngược bằng cách thêm !vào phía trước grepl- thử lại.
thelHRail

4
Hoặc sử dụng invertvà các valueđối số của grep. Biểu thức thông thường làm cho việc làm việc với văn bản dễ dàng hơn hàng ngàn lần.
Rich Scriven

4
@thelHRail greplkhông hoạt động trên postgres đối với tôi, đây có phải là MySQL không?
Statwonk

Câu trả lời:


255

Câu trả lời cho câu hỏi đã được đăng bởi @lHRail trong các bình luận ở trên. Bạn có thể sử dụng các biểu thức chính quy cho các đối số thứ hai và tiếp theo filternhư thế này:

dplyr::filter(df, !grepl("RTB",TrackingPixel))

Vì bạn chưa cung cấp dữ liệu gốc, tôi sẽ thêm một ví dụ đồ chơi bằng cách sử dụng bộ mtcarsdữ liệu. Hãy tưởng tượng bạn chỉ quan tâm đến những chiếc xe được sản xuất bởi Mazda hoặc Toyota.

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

Nếu bạn muốn thực hiện theo cách khác, cụ thể là loại trừ xe Toyota và Mazda, filterlệnh sẽ giống như sau:

dplyr::filter(mtcars, !grepl('Toyota|Mazda', type))

Nếu tên cột chứa một khoảng trắng. như theo dõi pixel.
MySchizoBuddy

3
đảm bảo bạn đang sử dụng chức năng lọc từ gói dplyr, không phải gói thống kê
JHowIX

2
@MySchizoBuddy: Nếu tên cột chứa khoảng trắng, bạn có thể chọn biến bằng backticks. Sửa đổi ví dụ trên: mtcars$`my type` <- rownames(mtcars)và sau đómtcars %>% filter(grepl('Toyota|Mazda', `my type`))
alex23lemm

13
lưu ý rằng đây không hoạt động khi đối tượng là một tbl_sqlnhư greplkhông dịch để sql.
David LeBauer

tùy chọn 1 là để biết chắc chắn rằng dplyr được tải sau cùng. tùy chọn 2 là tiền tố dplyr :: filter.
userJT

157

Giải pháp

Có thể sử dụng str_detectcác stringrgói bao gồm trong tidyversegói. str_detecttrả về Truehoặc Falsenhư là vectơ chỉ định có chứa một số chuỗi cụ thể. Có thể lọc bằng giá trị boolean này. Xem Giới thiệu về Stringr để biết chi tiết về stringrgói.

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

Những điều tốt về Stringr

Chúng ta nên sử dụng hơn stringr::str_detect()base::grepl(). Điều này là do có những lý do sau đây.

  • Các hàm được cung cấp bởi stringrgói bắt đầu bằng tiền tố str_, giúp mã dễ đọc hơn.
  • Đối số đầu tiên của các chức năng của stringrgói luôn là data.frame (hoặc giá trị), sau đó đến các tham số. (Cảm ơn bạn)
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"

Điểm chuẩn

Kết quả kiểm tra điểm chuẩn như sau. Đối với khung dữ liệu lớn, str_detectnhanh hơn.

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

1
Tại sao Stringr là một lựa chọn tốt hơn grep?
CameronNemo

2
@CameronNemo Các chức năng được cung cấp bởi stringrgói bắt đầu bằng tiền tố str_, giúp mã dễ đọc hơn. Trong mã R hiện đại gần đây, nên sử dụng stringr.
Keiku

3
Tôi nghĩ rằng đây là một sở thích cá nhân và tôi đồng ý với @CameronNemo base Rcũng tốt như vậy stringr. Nếu bạn sẽ cung cấp cho chúng tôi một số 'sự thật phũ phàng' như điểm chuẩn và không chỉ nêu rõ "nó được khuyến nghị" (Ai khuyên bạn nên làm điều đó?), Điều này sẽ được đánh giá cao. Cảm ơn
Tjebo

2
Một lý do khác là tính nhất quán trong khung tidyverse: đối số đầu tiên của hàm luôn là data.frame (hoặc giá trị), sau đó xuất hiện các tham số.
Paolo

22

Câu trả lời này tương tự như những người khác, nhưng sử dụng ưa thích stringr::str_detectvà 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

Được tạo vào ngày 2018-06-26 bởi gói reprex (v0.2.0).


1
str_detectcó trong stringrgói
jsta

3

chỉnh sửa bao gồm across()cú pháp mới hơn

Đây là một tidyversegiải pháp khác , sử dụng filter(across())hoặc trước đây filter_at. Ưu điểm là bạn có thể dễ dàng mở rộng đến nhiều hơn một cột .

Dưới đây cũng là một giải pháp filter_allđể tìm chuỗi trong bất kỳ cột nào , sử dụng diamondslàm ví dụ, tìm kiếm chuỗi "V"

library(tidyverse)

Chuỗi chỉ trong một cột

# 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

Cú pháp thay thế bây giờ cho cùng một sẽ là:

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

Chuỗi trong tất cả các cột:

# remove all rows where any column contains 'V'
diamonds %>%
  filter(across(everything(), ~ !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 Ideal   E     SI2      61.5    55   326  3.95  3.98  2.43
#> 2  0.21 Premium E     SI1      59.8    61   326  3.89  3.84  2.31
#> 3  0.31 Good    J     SI2      63.3    58   335  4.34  4.35  2.75
#> 4  0.3  Good    J     SI1      64      55   339  4.25  4.28  2.73
#> 5  0.22 Premium F     SI1      60.4    61   342  3.88  3.84  2.33
#> 6  0.31 Ideal   J     SI2      62.2    54   344  4.35  4.37  2.71

Cú pháp thay thế bây giờ cho cùng một sẽ là:

diamonds %>% 
  filter_all(all_vars(!grepl('V', .))) %>%
  head

Tôi đã cố gắng tìm một giải pháp thay thế cho những điều sau đây, nhưng tôi đã không ngay lập tức đưa ra một giải pháp tốt:

    #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

Cập nhật: Cảm ơn người dùng Petr Kajzar trong câu trả lời này , đây cũng là một cách tiếp cận cho vấn đề trên:

diamonds %>%
   filter(rowSums(across(everything(), ~grepl("V", .x))) > 0)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.