#r #dplyr
Вопрос:
Мне нужно что-то вроде CTRL Fв Microsoft Excel, чтобы искать строку во всем фрейме данных (я предпочитаю dplyr
решение, если это возможно).
Я изменил свой репрекс, основываясь на предложениях Ронака и Акруна. Они оба превосходны, один полагается на базу R, а другой-на str_detect. Лично я предпочитаю последнее только потому, что оно лучше работает с большими наборами данных на моей машине. Спасибо вам обоим!
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(stringr)
##Two functions suggested by Ronak
find_text <- function(df, tt, ...){
res <- df %>%
mutate(across(where(is.character), ~grepl(tt,.x, ...)))
return(res)
}
find_text_filter <- function(df, tt, ...){
res <- df %>%
filter(if_any(where(is.character), ~grepl(tt,.x, ...)))
return(res)
}
### And now the str_detect variation by Akrun
find_text2 <- function(df, tt){
res <- df %>%
mutate(across(where(is.character), ~str_detect(.x,tt)))
return(res)
}
find_text_filter2 <- function(df, tt){
res <- df %>%
filter(if_any(where(is.character), ~str_detect(.x,tt)))
return(res)
}
df <- tibble(a=seq(5), b=c("hfh", "gjgkjguk", "jyfyujyuj ygujyg", "uyyhjg",
"776uj"),
d=c("ggg", "hhh", "gfrr", "67hn", "jnug"),
e=c("gtdfdc", " kjihi", "hgwjhfg", "ujyggg", "ut 089jhjm") )
df1 <- df %>%
find_text("gj")
df1 ## this works: I know in which text column and where the text appears
#> # A tibble: 5 x 4
#> a b d e
#> <int> <lgl> <lgl> <lgl>
#> 1 1 FALSE FALSE FALSE
#> 2 2 TRUE FALSE FALSE
#> 3 3 FALSE FALSE FALSE
#> 4 4 FALSE FALSE FALSE
#> 5 5 FALSE FALSE FALSE
## and now this also does
df2 <- df %>%
find_text_filter("gj")
df2
#> # A tibble: 1 x 4
#> a b d e
#> <int> <chr> <chr> <chr>
#> 1 2 gjgkjguk hhh " kjihi"
### same with the str_detect functions
df3 <- df %>%
find_text2("gj")
df3
#> # A tibble: 5 x 4
#> a b d e
#> <int> <lgl> <lgl> <lgl>
#> 1 1 FALSE FALSE FALSE
#> 2 2 TRUE FALSE FALSE
#> 3 3 FALSE FALSE FALSE
#> 4 4 FALSE FALSE FALSE
#> 5 5 FALSE FALSE FALSE
df4 <- df %>%
find_text_filter2("gj")
df4
#> # A tibble: 1 x 4
#> a b d e
#> <int> <chr> <chr> <chr>
#> 1 2 gjgkjguk hhh " kjihi"
Создано 2021-05-20 пакетом reprex (v2.0.0)
Комментарии:
1. Я думаю, что вы хотите
~.x
, а не.~x
Ответ №1:
Мы могли бы использовать str_detect
library(dplyr)
library(stringr)
find_text_filter <- function(df, tt){
df %>%
filter(if_any(where(is.character), ~str_detect(.x, tt)))
}
-тестирование
df %>%
find_text_filter("gj")
# A tibble: 1 x 4
# a b d e
# <int> <chr> <chr> <chr>
#1 2 gjgkjguk hhh " kjihi"
Комментарии:
1. Тоже хорошая идея. Вероятно, быстрее, чем при использовании grepl.
2. Что-то не сходится. Если я попробую свой пример с str_detect вместо grepl, я не найду никакого соответствия…
3.
str_
функции @larry77stringr
основаны наstringi
, и это очень быстро4. Я думаю, что проблема была в том, что у
...
asstr_detect
есть только один дополнительный параметрnegate
, а остальные-это модифицирующие, то естьfixed(yourpattern)
5. Извините, я перевернул аргументы внутри str_detect. Починю почту завтра.
Ответ №2:
Вы можете воспользоваться if_any
здесь :
library(dplyr)
find_text_filter <- function(df, tt, ...){
res <- df %>%
filter(if_any(where(is.character), ~grepl(tt,.x, ...)))
return(res)
}
df %>% find_text_filter("gj")
# A tibble: 1 x 4
# a b d e
# <int> <chr> <chr> <chr>
#1 2 gjgkjguk hhh " kjihi"
Комментарии:
1. Спасибо! В точку!
Ответ №3:
Вы можете суммировать по строкам и выбирать только в том случае, если сумма > 0:
find_text_filter <- function(df, tt, ...){
res <- df %>%
mutate(across(where(is.character), ~grepl(tt,.x, ...))) %>% rowwise() %>%
filter(max(sum(c_across(where(is.logical)))) == 1)
return(res)
}