这是一个两步解决方案。首先,使用前 n 个字符进行模糊匹配和替换的函数。它运行agrepl
以将输入模式与提供的向量匹配,并在匹配时保持第一个n
字符。如果没有匹配,则返回NA
. 这旨在应用于模式向量 via lapply
,因此第二个函数旨在Reduce
将其转换为一个向量。 接受两个相同长度的向量,并用第二个的非缺失值reducer
替换第一个的所有实例,其中第二个不是。NA
这一切都包含在几个调用中,并根据需要返回向量。
fuzzy_match_and_replace = function(pattern, vector, n = 3){
n = min(c(n,nchar(pattern)))
match = agrepl(pattern,vector)
pattern_first_n = substr(pattern,1,n)
vector_first_n = substr(vector,1,n)
output = rep(NA,length(vector))
output[match & pattern_first_n == vector_first_n] = pattern_first_n
return(output)
}
reducer = function(a,b){
a[!is.na(b)] = b[!is.na(b)]
return(a)
}
df1 <- data.frame(var1 = c("abcd", "efgh", "ijkl", "mnopqr", "qrst"), stringsAsFactors = FALSE)
vec <- c("ab", "mnop", "ijk")
Reduce(reducer,lapply(vec,fuzzy_match_and_replace,vector=df1$var1),init=df1$var1)
#> [1] "ab" "efgh" "ijk" "mno" "qrst"
如果您希望它在 mutate 步骤中工作,您可以使用如下包装器
wrapper = function(pattern, vector, n = 3){
Reduce(reducer,lapply(pattern,fuzzy_match_and_replace,vector=vector,n=n),init=vector)
}
更新
这是一个更简单的函数(1 步),它利用adist
Onyambu 的答案但不依赖max.col
,而是使用vapply
它遍历矩阵来识别匹配并进行替换。
fuzzy_match_and_replace = function(pattern, vector, n = 3, ...){
matches = adist(pattern,vector,partial=T,...) == 0
replace = vapply(apply(matches,2,which)
,function(x){
if(length(x) > 0) return(substr(pattern,1,n)[x]) else return(NA_character_)
}
,FUN.VALUE = c(""))
vector[!is.na(replace)] = replace[!is.na(replace)]
return(vector)
}
library(dplyr)
df1 <- tibble(var1 = c("abcd", "efgh", "ijkl", "mnopqr", "qrst","mnopr"))
vec <- c("ab", "mnop", "ijk")
df1%>%
mutate(var1=fuzzy_match_and_replace(vec,var1))
#> # A tibble: 6 x 1
#> var1
#> <chr>
#> 1 ab
#> 2 efgh
#> 3 ijk
#> 4 mno
#> 5 qrst
#> 6 mno