使用R中的data.table进行不完整的字符串匹配

时间:2014-02-13 19:20:36

标签: string r performance text data.table

好的,所以我不久前发布了一个关于编写R函数以加速大文本文件串匹配的问题。我把眼睛打开了'data.table',我的问题得到了很好的回答。

这是指向该主题的链接,其中包含所有数据和详细信息:

Accelerate performance and speed of string match in R

但现在我遇到了另一个问题。偶尔,提交的VIN#s(在'vinDB'文件中)在'carFile'文件中由于人为错误而在DMV上填写他们的汽车信息时相差一两个字符。有没有办法编辑

dt[J(car.vins), list(NumTimesFound=.N), by=vin.names]

该代码的行(由@BrodieG在上面的链接中提供)允许识别相差一个或两个字符的VIN#?

如果这是一个简单的修正,我道歉。我只是被R中'data.table'软件包的力量所震撼,并希望尽可能多地学习它的实用性,而且这个论坛的知识渊博的成员对我来说绝对是关键。

**编辑:

所以我一直在玩'lapply'和'agrep'功能,我必须做错事:

我尝试更换此行:

dt[J(car.vins), list(NumTimesFound=.N), by=vin.names]

用这个:

dt <- dt[lapply(vin.vins, function(x) agrep(x,car.vins, max.distance=2)), list(NumTimesFound=.N), vin.names, allow.cartesian=TRUE]

但是出现了以下错误:

Error in `[.data.table`(dt, lapply(vin.vins, function(x) agrep(x,car.vins,  : 
x.'vin.vins' is a character column being joined to i.'V1' which is type 'integer'. 
Character columns must join to factor or character columns.

但他们都是'chr'型。有谁知道我为什么会收到这个错误?我是否正确地思考这个问题,即:我在这里正确使用lapply吗?

谢谢!

2 个答案:

答案 0 :(得分:4)

我终于明白了。

'agrep'函数有一个'value'选项需要从FALSE(默认)更改为true:

>dt <- dt[lapply(car.vins, agrep, x=vin.vins, max.distance=c(cost=2, all=2), value=TRUE), list(NumTimesFound=.N), vin.names]

注意:max.distance参数可以根据Levenshtein距离,替换,删除等进行更改.'agrep'是一个非常有趣的功能!

再次感谢您的帮助!

答案 1 :(得分:0)

感谢您对部分匹配问题的回答。这是我在自己的机器上工作的完整代码(包括BrodieG在您的链接帖子中提供的可重现的示例)。我必须将lapply更改为sapply

library(data.table)
set.seed(1)
makes <- c("Toyota", "Ford", "GM", "Chrysler")
years <- 1995:2014
cars <- paste(sample(makes, 500, rep=T), sample(years, 500, rep=T))
vins <- unlist(replicate(500, paste0(sample(LETTERS, 16), collapse="")))
vinDB <- data.frame(c(cars, vins)[order(rep(1:500, 2))])               
carFile <- data.frame(c(rep("junk", 1000), sample(vins, 1000, rep=T), rep("junk", 2000))[order(rep(1:1000, 4))])

vin.names <- vinDB[seq(1, nrow(vinDB), 2), ]
vin.vins <- vinDB[seq(2, nrow(vinDB), 2), ]
car.vins <- carFile[seq(2, nrow(carFile), 4), ]`

#Add some errors to car.vins strings
s <- sample(length(car.vins),100)
car.vins.err <- as.character(car.vins)
car.vins.err[s] <- gsub("A","B",car.vins.err[s])
s <- sample(length(car.vins.err),100)
car.vins.err[s] <- gsub("E","F",car.vins.err[s])
s <- sample(length(car.vins.err),100)
car.vins.err[s] <- gsub("I","J",car.vins.err[s])
car.vins.err <- as.factor(car.vins.err)`

dt <- data.table(vin.names, vin.vins, key="vin.vins")
dt1 <- dt[J(car.vins), list(NumTimesFound=.N), keyby=vin.names]
dt1.err <- dt[J(car.vins.err), list(NumTimesFound=.N), keyby=vin.names]
dt2 <- dt[sapply(car.vins, agrep, x=vin.vins, max.distance=c(cost=2, all=2), value=TRUE), list(NumTimesFound=.N), keyby=vin.names]
dt2.err <- dt[sapply(car.vins.err, agrep, x=vin.vins, max.distance=c(cost=2, all=2), value=TRUE), list(NumTimesFound=.N), keyby="vin.names"]

dt1[dt1.err][dt2.err]