有没有办法在dplyr中使用for循环来减少所需的str_detect项的数量?

时间:2019-04-28 00:44:20

标签: r dplyr stringr

我目前正在研究一个项目,并且我正在根据其内容对大约十万个字符串进行分类。

此代码的目标是识别字符串是否匹配,将其分类到特定存储桶,然后将最终结果保存到csv。没有代码包含多个匹配字符串。

我意识到,在某个点之后,我的代码变得有点不可读-主要是因为如果我不得不更改200个具有相同格式的str_detect函数之一,那么我就必须在case_when中找到它,等等,< / p>

我正在寻找一种可能集成循环以及是否有条件将其集成到函数中以提高可读性并简化str_detect函数修改的方法。

我尝试通过定义包含所有字符串类,字符串项和分类的小标题来替换出case_when / str_detect组合。之后,我将case_when换成了for循环,该循环将小节集成在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_type)的表。

for循环不起作用-它发出一个错误,指出“没有适用于'type'的适用方法应用于类别为“ c('tbl_df','tbl','data.frame')”的对象。

有人对我如何能够使它起作用有想法吗?

2 个答案:

答案 0 :(得分:0)

这是一种只使用一次Clips的方法。这里的问题是您不能使用普通联接来匹配,因为字符串可能包含其他字符。在这里,我要做的是将所有字符串匹配以匹配为一个模式以进行提取,因此我们可以添加一个新列。请注意,这样做是安全的,因为您说每一行只有一个匹配的字符串,尽管您应该检查一下(否则str_detect的顺序很重要)。不过,在连接字符串以进行匹配之前,我们必须转义特殊字符。

您还应确保我对case_when的解释与您的实际数据相符,或包含样本的food_set

dput

reprex package(v0.2.1)于2019-04-27创建

答案 1 :(得分:0)

这也可以用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