这是一个数据框和一个向量。
df1 <- tibble(var1 = c("abcd", "efgh", "ijkl", "mnopqr", "qrst"))
vec <- c("ab", "mnop", "ijk")
现在,对于 var1 中与 vec 中的值最接近的所有值(我想匹配前 n 个字符),仅保留 var1 中 vec 的前 3 个字符,这样所需的解决方案是:
df2 <- tibble(var1 = c("ab", "efgh", "ijk", "mno", "qrst"))
由于“abcd”与 vec 中的“ab”最匹配,因此我们在 df2 中仅保留最多 3 个“ab”字符,即本例中的 2 个,但 vec 中不存在“efgh”,因此我们保留它原样,即 df2 中的“efgh”等等。
我可以使用 dplyr、stringr、fuzzyjoin、agrep 或 fuzzywuzzyr 来完成此操作吗?您可能希望以此处建议的以下内容为基础 https://stackoverflow.com/a/51053674/6762788 ,感谢 Psidom。
df1 %>%
mutate(var1 = ifelse(var1 %in% vec, substr(var1, 1, 3), var1))
最佳答案
这是一个两步解决方案。首先,执行模糊匹配并替换前 n 个字符的函数。它运行 agrepl 将输入模式与提供的向量进行匹配,并保留前 n 个字符(如果匹配)。如果没有匹配,则返回NA
。其设计目的是通过 lapply 应用于模式向量,因此第二个函数用于将其转换为一个向量。 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"
如果您希望它在变异步骤中工作,您可以使用如下所示的包装器
wrapper = function(pattern, vector, n = 3){
Reduce(reducer,lapply(pattern,fuzzy_match_and_replace,vector=vector,n=n),init=vector)
}
更新
这是一个更简单的函数(1 步),它利用了 Onyambu 答案中的 adist
,但不依赖 max.col
,而是使用 vapply
code> 它会遍历矩阵来识别匹配并进行替换。
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
关于r - R中的部分字符串匹配并修剪字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51088502/