我想创建一个函数,它接受一个字符串列表,并将它们与包含多个(> 100)列的数据框中的字符串进行匹配。然后将所有匹配的字符串返回到新的数据帧中。换句话说,函数开始在col1中查找string1并在找到时停止。如果string4没有在col1中找到它,但在col2中,所以它只返回string2。如果是字符串3,它会停止,但string6会返回string3。
strings<-c("string1", "string2", "string3", "string4", "string5", "string6")
DF
col1 col2 col3
string1 x x
string2 string4 x
string3 string5 string6
dput(DF)
structure(list(col1 = structure(1:3, .Label = c("string1 x x",
"string2 string4 x", "string3 string5 string6"), class = "factor"),
col2 = c(NA, NA, NA), col3 = c(NA, NA, NA)), .Names = c("col1",
"col2", "col3"), class = "data.frame", row.names = c(NA, -3L))
df_new
col_combo
string1
string2
string3
string2
string3
string3
答案 0 :(得分:1)
您在上次评论中提示您正在寻找查找同义词的函数,这有助于提供答案。以下答案肯定不是最优雅的,也不是最快的。如果要查找大量同义词,可以查看data.table
的解决方案,这是此类查找任务的最快包。但是,为了让你前进,我只会使用基础R.(请注意,我已经重写了你的数据,因为你的df结构对我没有意义,我希望我对你的数据的理解是正确的。)< / p>
更新:根据折叠行中的搜索引入了其他选项,其中一个包含'stringi'包和一个data.table
appraoch。还添加了一个不匹配的"string7"
。此外,使用microbenchmark
引入了基准。我的data.table
方法似乎不是最好的,此外,该软件包带来了小数据集的一定开销,只有较大的数据集才具有明显的速度优势。您可以提供更大的可重现示例,可能基于此问题link中使用的函数,以便更好地进行比较。但是,应该注意的是,data.table对于精确匹配可能更快,请检查?%like%
。我测试的其他功能必须进行公平比较,也可以使用包fmatch
。
strings <- c("string1", "string2", "string3", "string4", "string5", "string6", "string7")
df <- read.table(text = "col1 col2 col3
string1 x x
string2 string4 x
string3 string5 string6"
,stringsAsFactors = F,header =T)
find_synonyms <- function(df, strings) {
sapply(strings, function(x) {
synonyms <- apply(df, 1, function(y) {
#you could also use match()
#grep() allows partial matching if needed
if(any(grepl(paste0("^",x,"$"), y))) {
y[1]
} else {
NA
}
})
synonyms[!(is.na(synonyms))]
})
}
find_synonyms_collapse_rows_grepl <- function(df, strings) {
synsets <- apply(df, 1, paste, collapse = " ")
names(synsets) <- df[,1]
sapply(strings, function(x) {
names(synsets)[grep(paste0("\\b", x ,"\\b"), synsets, perl=T)]
})
}
library(stringi)
find_synonyms_collapse_rows_stringi <- function(df, strings) {
synsets <- apply(df, 1, paste, collapse = " ")
names(synsets) <- df[,1]
sapply(strings, function(x) {
names(synsets)[stri_detect_regex(synsets, paste0("\\b", x ,"\\b"))]
})
}
library(data.table)
find_synonyms_DT_reshape_like <- function(df, strings) {
df <- as.data.table(df)
df[ , mainsynonym := col1]
df <- melt(df, id.vars = "mainsynonym")
setkey(df, value)
sapply(strings, function(x) {
df[value %like% x, mainsynonym]
})
}
find_synonyms_DT_matchkey <- function(df, strings) {
df <- as.data.table(df)
df[ , mainsynonym := col1]
df <- melt(df, id.vars = "mainsynonym")
setkey(df, value)
sapply(strings, function(x) {
df[value == x , mainsynonym]
})
}
results_list <- list(unlist(find_synonyms(df, strings)),
unlist(find_synonyms_collapse_rows_grepl(df, strings)),
unlist(find_synonyms_collapse_rows_stringi(df, strings)),
unlist(find_synonyms_DT_reshape_like(df, strings)),
unlist(find_synonyms_DT_matchkey(df, strings))
)
sapply(results_list, function(x) {
sapply(results_list, function(y) {
identical(x,y)
})
}
)
# [,1] [,2] [,3] [,4] [,5]
# [1,] TRUE TRUE TRUE TRUE TRUE
# [2,] TRUE TRUE TRUE TRUE TRUE
# [3,] TRUE TRUE TRUE TRUE TRUE
# [4,] TRUE TRUE TRUE TRUE TRUE
# [5,] TRUE TRUE TRUE TRUE TRUE
library(microbenchmark)
microbenchmark(
find_synonyms(df, strings),
find_synonyms_collapse_rows_grepl(df, strings),
find_synonyms_collapse_rows_stringi(df, strings),
find_synonyms_DT_reshape_like(df, strings),
find_synonyms_DT_matchkey(df, strings)
)
# Unit: microseconds
# expr min lq mean median uq max neval
# find_synonyms(df, strings) 719.624 848.5085 1129.4298 987.6565 1058.9080 9290.361 100
# find_synonyms_collapse_rows_grepl(df, strings) 660.017 738.1770 952.7571 794.8230 839.4295 16998.577 100
# find_synonyms_collapse_rows_stringi(df, strings) 223.428 265.8625 364.4979 302.9685 344.4170 5798.433 100
# find_synonyms3_DT_reshep_like(df, strings) 3259.029 3643.9060 3900.1955 3800.8180 4102.7985 5883.303 100
# find_synonyms_DT_matchkey(df, strings) 4710.135 4907.9040 5428.8650 5279.5595 5630.8855 8450.769 100