Есть ли способ использовать циклы for внутри dplyr, чтобы уменьшить количество необходимых терминов str_detect? - PullRequest
1 голос
/ 28 апреля 2019

В настоящее время я работаю над проектом и пытаюсь классифицировать около ста тысяч строк на основе их содержания.

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

Я понимаю, что после определенного момента мой код становится немного нечитаемым - в основном потому, что если мне нужно изменить одну из, скажем, двухсот функций str_detect с тем же форматом, я должен найти его в своем case_when и т. Д.

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

Я попытался обменять комбинацию case_when / str_detect, определив тиббл, включающий все мои классы строк, строковые термины и классификации. После этого я заменил case_when для цикла for, который интегрирует tibble в str_detect, вытаскивая определенное условие строки каждый ход.

# Working case_when version

library(dplyr)
library(stringr)

a.str <- "(?i)Apple"
b.str <- "(?i)Banana"
c.str <- "(?i)Corn"

food_set <- read_csv("Food.csv")

food_identified <- food_set %>% mutate(
     food.type = case_when( 
          str_detect(food_set, a.str ) = TRUE ~ "A",
          str_detect(food_set, b.str ) = TRUE ~ "B",
          str_detect(food_set, c.str ) = TRUE ~ "C"
     )
)

food_classified <- write_csv(food_identified,"Food_Classified.csv")
# Failing for loop version


library(dplyr)
library(stringr)

str_options <- tribble(
~variety.str,      ~String,   ~Classification,
#-----------/-------------/-------------------
"a.str"     , "(i?)Apple" ,               "A",
"b.str"     , "(i?)Banana",               "B",
"c.str"     , "(i?)Corn"  ,               "C"
)

food_set <- read_csv("Food.csv")

food_identified <- food_set %>% mutate(
     for (k in 1:3) {
          if(str_detect(food_set, str_options[k,2]) == TRUE) {
          food.type = str_options[k,3]
     }
     break
     }
)

food_classified <- write_csv(food_identified,"Food_Classified.csv")

Код case_when работает нормально - он выплевывает таблицу с двумя столбцами (food, food_type).

Цикл for не работает - он выдает ошибку, в которой говорится, что «нет применимого метода для типа», примененного к объекту класса «c (« tbl_df »,« tbl »,« data.frame »)».

Кто-нибудь имеет представление о том, как я мог бы заставить это работать?

Ответы [ 2 ]

0 голосов
/ 28 апреля 2019

Это также можно сделать с помощью fuzzyjoin.Одно потенциальное преимущество / вещь, на которую стоит обратить внимание, - это то, что он присоединится ко всем соответствующим регулярным выражениям.

library(tidyverse); library(fuzzyjoin)
food_set <- tibble(
  food_set = c("sadgad(i?)Apple", "(i?)Bananaasdgas", "hgjdndg(i?)Cornadfba")
)

food_set %>%
  regex_left_join(str_options, by = c("food_set" = "String"))


# A tibble: 3 x 4
  food_set             variety.str String     Classification
  <chr>                <chr>       <chr>      <chr>         
1 sadgad(i?)Apple      a.str       (i?)Apple  A             
2 (i?)Bananaasdgas     b.str       (i?)Banana B             
3 hgjdndg(i?)Cornadfba c.str       (i?)Corn   C  
0 голосов
/ 28 апреля 2019

Вот способ, который просто использует один вызов str_detect.Проблема здесь в том, что вы не можете использовать обычное соединение для сопоставления, потому что строки могут содержать другие символы.Здесь я объединяю все строки для сопоставления в один шаблон для извлечения, поэтому у нас есть новый столбец, к которому можно присоединиться.Обратите внимание, что это безопасно только потому, что вы сказали, что каждая строка будет иметь только одну совпадающую строку, хотя вы должны проверить это (в противном случае порядок case_when будет иметь значение).Тем не менее, мы должны экранировать специальные символы, прежде чем присоединять соответствующие строки.

Вы также должны убедиться, что моя интерпретация food_set соответствует вашим фактическим данным или включить dput выборки.

library(tidyverse)

food_set <- tibble(
  food_set = c("sadgad(i?)Apple", "(i?)Bananaasdgas", "hgjdndg(i?)Cornadfba")
)

str_options <- tribble(
  ~variety.str,      ~String,   ~Classification,
  #-----------/-------------/-------------------
  "a.str"     , "(i?)Apple" ,               "A",
  "b.str"     , "(i?)Banana",               "B",
  "c.str"     , "(i?)Corn"  ,               "C"
)

str_regex <- str_options$String %>%
  str_replace_all("(\\W)", "\\\\\\1") %>%
  str_c(collapse = "|")

food_set %>%
  mutate(to_match = str_extract(food_set, str_regex)) %>%
  left_join(str_options, by = c("to_match" = "String"))
#> # A tibble: 3 x 4
#>   food_set             to_match   variety.str Classification
#>   <chr>                <chr>      <chr>       <chr>         
#> 1 sadgad(i?)Apple      (i?)Apple  a.str       A             
#> 2 (i?)Bananaasdgas     (i?)Banana b.str       B             
#> 3 hgjdndg(i?)Cornadfba (i?)Corn   c.str       C

Создано в 2019-04-27 пакетом Представить (v0.2.1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...