Использование stringi с блестящим для поиска фрейма данных выдает предупреждения

Я сделал блестящее приложение для поиска в одном большом фрейме данных и подумал об использовании stringi. Однако, когда я запускаю приложение, я получаю предупреждение о том, что пустые шаблоны поиска не поддерживаются. С этим примером приложения я могу просто игнорировать это предупреждение (хотя оно продолжает рассылать спам), однако с моим приложением с большим фреймом данных все замедляется, и единственный способ, которым я могу остановить приложение, — это завершить сеанс R.

## app.R ##
require(shiny)
require(stringi)
require(dplyr)
require(DT)

ui <- fluidPage(textInput("searchall", label =  "Search"),
            dataTableOutput("tableSearch"))

server <- function(input, output, session) {
  data(GNI2014)
  output$tableSearch <- DT::renderDataTable(datatable(
  GNI2014 %>% filter(
      if (!is.null(input$searchall))
        stri_detect_fixed(str = country , pattern = input$searchall)
    ),
    options = list(sDom  = '<"top">lrt<"bottom">ip')
  ))
}

shinyApp(ui, server)

Когда я запускаю это приложение, я получаю следующее предупреждение:

Предупреждение в stri_detect_fixed(str = country, pattern = input$searchall): пустые шаблоны поиска не поддерживаются

Как лучше всего обойти это предупреждение и связанное с ним замедление.


person magasr    schedule 20.12.2017    source источник


Ответы (1)


Вам не нужно stringi() для этого. Самый быстрый способ запросить данные — использовать data.table() с ключом на country и использовать grepl() для подмножества данных.

Пример с использованием данных GNI2014 из пакета treemap.

library(treemap)
library(data.table)
data(GNI2014)
gni2014table <- data.table(GNI2014)
setkey(gni2014table,"country")
searchText <- "berm"
gni2014table[grepl(searchText,gni2014table$country,ignore.case=TRUE),]

searchText <- "United"
gni2014table[grepl(searchText,gni2014table$country,ignore.case=TRUE),]

...и вывод.

> library(treemap)
> library(data.table)
> data(GNI2014)
> gni2014table <- data.table(GNI2014)
> setkey(gni2014table,"country")
> searchText <- "berm"
> gni2014table[grepl(searchText,gni2014table$country,ignore.case=TRUE),]
   iso3 country     continent population    GNI
1:  BMU Bermuda North America      67837 106140
> 
> searchText <- "United"
> gni2014table[grepl(searchText,gni2014table$country,ignore.case=TRUE),]
   iso3              country     continent population   GNI
1:  ARE United Arab Emirates          Asia    4798491 44600
2:  GBR       United Kingdom        Europe   62262000 43430
3:  USA        United States North America  313973000 55200
>

Возврат только столбца, поле которого вы хотите заполнить в пользовательском интерфейсе, выглядит следующим образом.

searchText <- "United Arab"
gni2014table[grepl(searchText,gni2014table$country,ignore.case=TRUE),country]

ОБНОВЛЕНИЕ 20 декабря 2017 г.: добавлен код для запуска микробенчмарков, показывающий, что в первом тестовом примере lgrepl() выполняется на 20 мс быстрее, чем stringi_detect_fixed(), а во втором случае stringi_detect_fixed() на 60 мс быстрее, чем lgrepl() для 100 итераций теста. запрос.

library(treemap)
library(data.table)
library(microbenchmark)
data(GNI2014)
gni2014table <- data.table(GNI2014)
setkey(gni2014table,"country")
searchText <- "berm"

microbenchmark(gni2014table[grepl(searchText,gni2014table$country,
                                  ignore.case=TRUE),])

searchText <- "United Arab"
microbenchmark(gni2014table[grepl(searchText,gni2014table$country,
                                  ignore.case=TRUE),country])

library(stringi)
searchText <- "berm"

microbenchmark(gni2014table[stri_detect_fixed(searchText,
                              gni2014table$country,
                              case_insensitive=TRUE),])

searchText <- "United Arab"

microbenchmark(gni2014table[stri_detect_fixed(searchText,
                            gni2014table$country,case_insensitive=TRUE),])

Вам придется запустить код самостоятельно, чтобы воспроизвести тесты, потому что вывод microbenchmark() не отображается легко на SO.

Тем не менее, обобщенная версия таймингов такова:

searchText      Function             Mean (in Microseconds)
-------------   -------------------- -----------------------
berm            grepl                526.2545
United Arab     grepl                583.1789
berm            stringi_detect_fixed 545.8772
United Arab     stringi_detect_fixed 524.1132
person Len Greski    schedule 20.12.2017
comment
Спасибо за ответ. Я подумал, что srtingi будет предпочтительным вариантом, учитывая, что у меня есть большой фрейм данных с большим куском текста в каждом поле, и учитывая выводы здесь: stackoverflow .com/q/24257850/3967488 - person magasr; 20.12.2017
comment
@magasr URL-адрес, который вы разместили, включает конфликтующие тайминги, где один ответ показывает, что grepl() быстрее, чем stringi_detect_fixed(), а другой указывает на обратное. Я обновлю свой пост, включив в него микробенчмарки для вашей актуальной проблемы, и вы увидите, что, когда я кодировал решение, один поиск выполняется быстрее с помощью grepl(), а другой быстрее с помощью stringi_detect_fixed(). Тем не менее, результаты для 100 итераций каждого вызова находятся в пределах 60 миллисекунд друг от друга или практически неразличимы на основе отдельного вызова. - person Len Greski; 20.12.2017
comment
редактировать: ... результаты для 100 итераций находятся в пределах 60 микросекунд друг от друга. - person Len Greski; 20.12.2017