Цикл grepl () через данные.таблицы (R)

у меня есть набор данных, хранящихся в данных.таблица DT это выглядит так:

print(DT)
   category            industry
1: administration      admin
2: nurse practitioner  truck
3: trucking            truck
4: administration      admin
5: warehousing         nurse
6: warehousing         admin
7: trucking            truck
8: nurse practitioner  nurse         
9: nurse practitioner  truck 

Я хотел бы уменьшить таблицу только до строк, где отрасль соответствует категории. Мой общий подход-использовать grepl() для регулярного выражения соответствует строке '^{{INDUSTRY}}[a-z ]+$' и каждый ряд DT$category, С каждой соответствующей строки DT$industry вставить вместо {{INDUSTRY}} в строке регулярного выражения с помощью infuse(). Я изо всех сил пытался найти гладкие данные.решение таблицы, которое будет правильно проходить через таблицу и сделайте сравнения внутри строки, поэтому я прибегнул к for-loop, чтобы выполнить работу:

template <- "^{{IND}}[a-z ]+$"
DT[,match := FALSE,]
for (i in seq(1,length(DT$category))) {
    ind <- DT[i]$industry
    categ <- d.daily[i]$category
    if (grepl(infuse(IND=ind,template),categ)){
        DT[i]$match <- TRUE
    }
}
DT<- DT[match==TRUE]
print(DT)
       category            industry
1: administration      admin
2: trucking            truck
3: administration      admin
4: trucking            truck
5: nurse practitioner  nurse         

тем не менее, я уверен, что это можно сделать лучше. Любые предложения о том, как я мог бы достичь этого результата, используя данные.функциональность пакета таблицы? Насколько я понимаю, в этом контексте подход, который использует пакет, вероятно, будет более эффективным, чем for-loop.

3 ответов


данные.таблица хороша в сгруппированных операциях; я думаю, что это может помочь, предполагая, что у вас много строк с той же отраслью:

DT[ DT[, .I[grep(industry, category)], by = industry]$V1 ]

использует текущая идиома для подстановки по группам, благодаря @eddi .


комментарии. это может помочь дальше:

  • Если у вас есть много строк с той же отраслевой категории комбо, попробуйте by=.(industry,category).

  • попробуйте что-то еще в место grep (как варианты в ответах Кена и Ричарда).


до тех пор, пока матч всегда основан на начале category string, тогда это работает просто отлично:

dt[substring(category, 1, nchar(industry)) == industry]
#              category industry
# 1:     administration    admin
# 2:           trucking    truck
# 3:     administration    admin
# 4:           trucking    truck
# 5: nurse practitioner    nurse

вы могли бы использовать stringi::stri_detect_fixed(). Он векторизован над обоими str и pattern.

DT[stringi::stri_detect_fixed(category, industry)]
#              category industry
# 1:     administration    admin
# 2:           trucking    truck
# 3:     administration    admin
# 4:           trucking    truck
# 5: nurse practitioner    nurse 

кроме того, stringr::str_detect() можно использовать. Он также векторизуется над обоими его аргументами.

library(stringr)
DT[str_detect(category, fixed(industry))]

или базовая опция R-запустить grepl() через mapply()

DT[mapply(grepl, industry, category, fixed = TRUE)]

или вы можете получить тот же результат с Vectorize(grepl).

DT[Vectorize(grepl)(industry, category, fixed = TRUE)]

все они дают один и тот же результат.

данные:

DT <- structure(list(category = c("administration", "nurse practitioner", 
"trucking", "administration", "warehousing", "warehousing", "trucking", 
"nurse practitioner", "nurse practitioner"), industry = c("admin", 
"truck", "truck", "admin", "nurse", "admin", "truck", "nurse", 
"truck")), .Names = c("category", "industry"), class = "data.frame", row.names = c(NA, 
-9L))
setDT(DT)