通过 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=industry
或by=.(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()
。它在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)
【讨论】:
有没有判断两者哪个“更好”?似乎矢量化应该击败循环隐藏,但我不确定。 @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 中获取随机的内部 selfref 错误