Jes*_* CT 3 r left-join grepl fuzzyjoin
我希望根据条件连接两个数据帧,在本例中,一个字符串位于另一个字符串内。假设我有两个数据框,
df1 <- data.frame(fullnames=c("Jane Doe", "Mr. John Smith", "Nate Cox, Esq.", "Bill Lee III", "Ms. Kate Smith"),
ages = c(30, 51, 45, 38, 20))
fullnames ages
1 Jane Doe 30
2 Mr. John Smith 51
3 Nate Cox, Esq. 45
4 Bill Lee III 38
5 Ms. Kate Smith 20
df2 <- data.frame(lastnames=c("Doe", "Cox", "Smith", "Jung", "Smith", "Lee"),
ages=c(30, 45, 20, 28, 51, 38),
homestate=c("NJ", "CT", "MA", "RI", "MA", "NY"))
lastnames ages homestate
1 Doe 30 NJ
2 Cox 45 CT
3 Smith 20 MA
4 Jung 28 RI
5 Smith 51 MA
6 Lee 38 NY
Run Code Online (Sandbox Code Playgroud)
我想对这两个数据帧的年龄和其中df2$lastnames包含的行进行左连接df1$fullnames。我想fuzzy_join可能会这样做,但我不认为它喜欢我的grepl:
joined_dfs <- fuzzy_join(df1, df2, by = c("ages", "fullnames"="lastnames"),
+ match_fun = c("=", "grepl()"),
+ mode="left")
Error in which(m) : argument to 'which' is not logical
Run Code Online (Sandbox Code Playgroud)
期望的结果:与第一个数据框相同但附加了“homestate”列的数据框。有任何想法吗?
你只需要修复match_fun:
# ...
match_fun = list(`==`, stringr::str_detect),
# ...
Run Code Online (Sandbox Code Playgroud)
match_fun您的想法是正确的,但是您对 中参数的解释出错了fuzzyjoin::fuzzy_join()。根据文档,match_fun应该是
给定两列的矢量化函数,返回 TRUE 或 FALSE 以确定它们是否匹配。可以是函数列表,一个函数对应于中指定的每一对列
by(如果是命名列表,则使用 x 中的名称)。如果只给出一个函数,它将用于所有列对。
一个简单的更正就可以解决问题,并通过 进一步格式化dplyr。为了概念清晰,我在排版上将by列与function用于匹配它们的 s 对齐:
library(dplyr)
# ...
# Existing code
# ...
joined_dfs <- fuzzy_join(
df1, df2,
by = c("ages", "fullnames" = "lastnames"),
# |----| |-----------------------|
match_fun = list(`==` , stringr::str_detect ),
# |--| |-----------------|
# Match by equality ^ ^ Match by detection of `lastnames` in `fullnames`
mode = "left"
) %>%
# Format resulting dataset as you requested.
select(fullnames, ages = ages.x, homestate)
Run Code Online (Sandbox Code Playgroud)
鉴于此处复制的示例数据
df1 <- data.frame(
fullnames = c("Jane Doe", "Mr. John Smith", "Nate Cox, Esq.", "Bill Lee III", "Ms. Kate Smith"),
ages = c(30, 51, 45, 38, 20)
)
df2 <- data.frame(
lastnames = c("Doe", "Cox", "Smith", "Jung", "Smith", "Lee"),
ages = c(30, 45, 20, 28, 51, 38),
homestate = c("NJ", "CT", "MA", "RI", "MA", "NY")
)
Run Code Online (Sandbox Code Playgroud)
data.frame该解决方案应为生成以下内容joined_dfs,按要求格式化:
fullnames ages homestate
1 Jane Doe 30 NJ
2 Mr. John Smith 51 MA
3 Nate Cox, Esq. 45 CT
4 Bill Lee III 38 NY
5 Ms. Kate Smith 20 MA
Run Code Online (Sandbox Code Playgroud)
因为每个ages都是唯一的键,所以以下连接仅*names
fuzzy_join(
df1, df2,
by = c("fullnames" = "lastnames"),
match_fun = stringr::str_detect,
mode = "left"
)
Run Code Online (Sandbox Code Playgroud)
将更好地说明子字符串匹配的行为:
fullnames ages.x lastnames ages.y homestate
1 Jane Doe 30 Doe 30 NJ
2 Mr. John Smith 51 Smith 20 MA
3 Mr. John Smith 51 Smith 51 MA
4 Nate Cox, Esq. 45 Cox 45 CT
5 Bill Lee III 38 Lee 38 NY
6 Ms. Kate Smith 20 Smith 20 MA
7 Ms. Kate Smith 20 Smith 51 MA
Run Code Online (Sandbox Code Playgroud)
传递给的值match_fun应该是(symbolfor)afunction
fuzzyjoin::fuzzy_join(
# ...
match_fun = grepl
# ...
)
Run Code Online (Sandbox Code Playgroud)
或list这样的(symbols for )functions:
fuzzyjoin::fuzzy_join(
# ...
match_fun = list(`=`, grepl)
# ...
)
Run Code Online (Sandbox Code Playgroud)
而不是提供 a listof symbols
match_fun = list(=, grepl)
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)match_fun = c("=", "grepl()")
用户应命名该functions
`=`
grepl
Run Code Online (Sandbox Code Playgroud)
但你错误地试图称呼他们:
=
grepl()
Run Code Online (Sandbox Code Playgroud)
命名它们将按照预期将functions本身传递给match_fun,而调用它们将传递它们的返回值* 。在 R 中,类似的运算符=使用反引号命名:`=`。
* 假设调用没有因错误而失败。在这里,他们会失败。
要比较两个值是否相等(此处为character向量df1$fullnames和 )df2$lastnames,您应该使用关系运算符==;但您错误地提供了赋值运算符=。
此外,grepl()它并没有按照期望的方式进行矢量化match_fun。虽然它的第二个参数( x) 确实是一个向量
寻找匹配的字符向量,或者可以由 as.character 强制转换为字符向量的对象。支持长向量。
它的第一个参数( pattern) 被(视为)单个character字符串:
fixed = TRUE包含要在给定字符向量中匹配的正则表达式(或 的字符串)的字符串。如果可能的话,强制转换as.character为字符串。如果提供长度为 2 或以上的字符向量,则使用第一个元素时会发出警告。regexpr除了、gregexpr和 之外,允许缺失值regexec。
因此,grepl()不是一个
给定两列的向量化函数...
而是function给定一个字符串(标量)和一列(向量)字符串。
你祈祷的答案不是grepl(),而是类似的东西stringr::str_detect(),即
对
string和进行矢量化pattern。相当于grepl(pattern, x)。
由于您只是尝试检测文字字符串 in是否df1$fullnames包含文字字符串 in df2$lastnames,因此您不想意外地将字符串视为df2$lastnames正则表达式 模式。现在,您的df2$lastnames列在统计上不太可能包含具有特殊正则表达式字符的名称;唯一的例外是-,它按字面解释在 之外[],不太可能在名称中找到。
如果您仍然担心意外的正则表达式,您可能需要考虑使用或 的替代搜索方法。它们分别通过字节或“规范等价”执行文字匹配;后者根据区域设置和特殊字符进行调整,以与自然语言处理保持一致。stringi::stri_detect_fixed()stringi::stri_detect_coll()