R:使用 agrep 和 data.table 进行模糊合并
R: Fuzzy merge using agrep and data.table
我尝试合并两个 data.tables,但由于股票名称的拼写不同,我丢失了大量数据点。因此,我正在研究模糊合并,而不是完全匹配。
library("data.table")
dt1 = data.table(Name = c("ASML HOLDING","ABN AMRO GROUP"), A = c(1,2))
dt2 = data.table(Name = c("ASML HOLDING NV", "ABN AMRO GROUP"), B = c("p", "q"))
在"Name"上合并dt1和dt2时,ASML HOLDING会因为"NV"的加入而被排除在外,而实际数据是准确的。
首选的最终数据输出类似于:
Name A B
1: ABN AMRO GROUP 2 q
2: ASML HOLDING NV 1 p
我接下来尝试的是:
dt1 = dt1[, dt2_NAME := agrep(dt1$Name, dt2$Name, ignore.case = TRUE, value = TRUE, max.distance = 0.05, useBytes = TRUE)]
但是,我收到以下错误,
argument 'pattern' has length > 1 and only the first element will be used
错误是有道理的,因为 dt1$Name 比 1 长,但我相信如果它逐行考虑 dt1$Name 将是一个可能的解决方案。
这可能是一个愚蠢的错误,但出于某种原因我无法理解它。此外,我更喜欢使用 data.table,因为我的数据集相当大,而且到目前为止它运行良好。另外,我是堆栈溢出的新手,如果我的问题有点不对,很抱歉。
最后,我找到了一段代码可以完成这项工作,但对于实际使用来说太慢了。 Fuzzy merge in R
dt1$Name_dt2 <- "" # Creating an empty column
for(i in 1:dim(dt1)[1]) {
x <- agrep(dt1$Name[i], dt2$Name,
ignore.case=TRUE, value=TRUE,
max.distance = 0.05, useBytes = TRUE)
x <- paste0(x,"")
dt1$Name_dt2[i] <- x
}
使用'fuzzyjoin'的可能解决方案:
library(fuzzyjoin)
f <- Vectorize(function(x,y) agrepl(x, y,
ignore.case=TRUE,
max.distance = 0.05, useBytes = TRUE))
dt1 %>% fuzzy_inner_join(dt2, by="Name", match_fun=f)
# Name.x A Name.y B
#1 ASML HOLDING 1 ASML HOLDING NV p
#2 ABN AMRO GROUP 2 ABN AMRO GROUP q
注意:您也遇到的主要问题是 agrep
和 agrepl
似乎不希望第一个参数是向量。这就是我用 Vectorize
.
结束通话的原因
此方法可与等值连接一起使用(注意 by
中列的顺序!):
dt1 = data.frame(Name = c("ASML HOLDING","ABN AMRO GROUP"), A = c(1,2),Date=c(1,2))
dt2 = data.frame(Name = c("ASML HOLDING NV", "ABN AMRO GROUP", "ABN AMRO GROUP"), B = c("p", "q","r"),Date=c(1,2,3))
dt1 %>% fuzzy_inner_join(dt2, by=c("Date","Name"), match_fun=f) %>% filter(Date.x==Date.y)
我尝试合并两个 data.tables,但由于股票名称的拼写不同,我丢失了大量数据点。因此,我正在研究模糊合并,而不是完全匹配。
library("data.table")
dt1 = data.table(Name = c("ASML HOLDING","ABN AMRO GROUP"), A = c(1,2))
dt2 = data.table(Name = c("ASML HOLDING NV", "ABN AMRO GROUP"), B = c("p", "q"))
在"Name"上合并dt1和dt2时,ASML HOLDING会因为"NV"的加入而被排除在外,而实际数据是准确的。
首选的最终数据输出类似于:
Name A B
1: ABN AMRO GROUP 2 q
2: ASML HOLDING NV 1 p
我接下来尝试的是:
dt1 = dt1[, dt2_NAME := agrep(dt1$Name, dt2$Name, ignore.case = TRUE, value = TRUE, max.distance = 0.05, useBytes = TRUE)]
但是,我收到以下错误,
argument 'pattern' has length > 1 and only the first element will be used
错误是有道理的,因为 dt1$Name 比 1 长,但我相信如果它逐行考虑 dt1$Name 将是一个可能的解决方案。
这可能是一个愚蠢的错误,但出于某种原因我无法理解它。此外,我更喜欢使用 data.table,因为我的数据集相当大,而且到目前为止它运行良好。另外,我是堆栈溢出的新手,如果我的问题有点不对,很抱歉。
最后,我找到了一段代码可以完成这项工作,但对于实际使用来说太慢了。 Fuzzy merge in R
dt1$Name_dt2 <- "" # Creating an empty column
for(i in 1:dim(dt1)[1]) {
x <- agrep(dt1$Name[i], dt2$Name,
ignore.case=TRUE, value=TRUE,
max.distance = 0.05, useBytes = TRUE)
x <- paste0(x,"")
dt1$Name_dt2[i] <- x
}
使用'fuzzyjoin'的可能解决方案:
library(fuzzyjoin)
f <- Vectorize(function(x,y) agrepl(x, y,
ignore.case=TRUE,
max.distance = 0.05, useBytes = TRUE))
dt1 %>% fuzzy_inner_join(dt2, by="Name", match_fun=f)
# Name.x A Name.y B
#1 ASML HOLDING 1 ASML HOLDING NV p
#2 ABN AMRO GROUP 2 ABN AMRO GROUP q
注意:您也遇到的主要问题是 agrep
和 agrepl
似乎不希望第一个参数是向量。这就是我用 Vectorize
.
此方法可与等值连接一起使用(注意 by
中列的顺序!):
dt1 = data.frame(Name = c("ASML HOLDING","ABN AMRO GROUP"), A = c(1,2),Date=c(1,2))
dt2 = data.frame(Name = c("ASML HOLDING NV", "ABN AMRO GROUP", "ABN AMRO GROUP"), B = c("p", "q","r"),Date=c(1,2,3))
dt1 %>% fuzzy_inner_join(dt2, by=c("Date","Name"), match_fun=f) %>% filter(Date.x==Date.y)