通过 data.table (R) 循环 grepl()

Posted

技术标签:

【中文标题】通过 data.table (R) 循环 grepl()【英文标题】:Looping grepl() through data.table (R) 【发布时间】:2016-02-15 09:52:10 【问题描述】:

我有一个存储为 data.table 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 的每一行,使用infuse() 在正则表达式字符串中插入DT$industry 的每一对应行来代替INDUSTRY。我很难找到一个流畅的 data.table 解决方案,它可以正确地循环遍历表并进行行内比较,所以我求助于 for 循环来完成工作:

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         

但是,我相信这可以以更好的方式完成。关于如何通过使用 data.table 包的功能来实现此结果的任何建议?据我了解,在这种情况下,使用包的方法可能比 for 循环更有效。

【问题讨论】:

您的真实用例的参数尚不清楚,但我想by=industryby=.(industry, category) 可能会有所帮助(在以下任一答案中),减少所需的比较次数。 @Frank 所说的-按行业定期执行grep-我很确定这会比stringr 答案快得多(并且显然比子字符串更通用) - dt[dt[, grepl(industry, category), by = industry]$V1] @eddi by= 可能会重新排序数据,导致逻辑子集错误,可能是 DT[ DT[, .I[grep(industry, category)], by = industry]$V1 ] 来自 ***.com/a/16574176/1191259 你说得对 【参考方案1】:

您可以使用stringi::stri_detect_fixed()。它在strpattern 上进行了矢量化处理。

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)

【讨论】:

有没有判断两者哪个“更好”?似乎矢量化应该击败循环隐藏,但我不确定。 @Frank - 我猜mapply() 更好,因为它做的检查更少。 在 stringi 中很好地使用了矢量化匹配 - 它非常适合。【参考方案2】:

只要匹配始终基于category 字符串的开头,那么就可以了:

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

【讨论】:

【参考方案3】:

Data.table 擅长分组操作;我认为这就是它可以提供帮助的方式,假设您在同一行业有很多行:

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

这使用the current idiom for subsetting by group, thanks to @eddi 。


评论。这些可能会有所帮助:

如果您有许多行具有相同的行业类别组合,请尝试by=.(industry,category)

尝试用其他方法代替 grep(例如 Ken 和 Richard 的答案中的选项)。

【讨论】:

以上是关于通过 data.table (R) 循环 grepl()的主要内容,如果未能解决你的问题,请参考以下文章

R data.table 滑动窗口

在 R 的 data.table 中获取随机的内部 selfref 错误

R通过字符变量的值对data.table进行子集

通过R中的列的cumsum拆分data.table

通过引用传递函数时处理 R data.table 中的无效 selfref

R 中 data.table 的 colnames() 行为