我有两个数据框:
姓名 | 地点 |
---|---|
爱丽丝 | 伦敦/利物浦 |
鲍勃 | 曼彻斯特 |
吉姆 | 没有 |
大卫 | 我住在卡迪夫 |
我有另一个数据框(df2),它是英国城镇的单列列表,如下所示:
城市 |
---|
曼彻斯特 |
卡迪夫 |
伦敦 |
布莱顿 |
诺丁汉 |
我想做的是编写能够:
循环df1
对于位置列中的每个条目,扫描 df2,如果 df2 中的任何城市在 df1 中完全复制,则向 df 1 添加一个新列,以提取第一个匹配项,如下所示:
姓名 | 地点 | 位置_精确 |
---|---|---|
爱丽丝 | 伦敦或布莱顿 | 伦敦 |
鲍勃 | 曼彻斯特 | 曼彻斯特 |
吉姆 | 没有 | - |
大卫 | 我住在卡迪夫 | 卡迪夫 |
然后我可以使用 location_precise 列通过标准化名称进行进一步分析。常规 left_join/lapply 函数让我困惑的是,我想允许在一个方向上部分匹配(如果 df2 中的城市部分包含在 df1 中),但不允许在另一个方向上部分匹配(如果 df1$location 中的答案是df2 中的城市,例如上例中的“no”和“nottingham”。
我不知道如何使常规 dplyr 函数适应这一点,因为两个数据集中没有公共标识符 - 因此每次连接尝试都会以各种错误结束。否则我就完全束手无策了。我尝试过使用 grep:
df1$location_precise <- lapply(df1$Location, grep, df2$city,value=T)
但这不会获取没有空格的部分匹配项,例如“伦敦/格拉斯哥”
我也尝试过 agrep,但这会错误地识别部分匹配,例如 'No' = 'Nottingham',并且仍然无法识别许多其他部分匹配
始终记得放置一个可重现的示例。
我已经拿走了你的表(df1 和 df2),并为两个表添加了一个额外的案例:
df1 <- data.frame(Name = LETTERS[1:5],
Location = c("London/Liverpool",
"London/Glasgow",
"Manchester",
"No",
"I am based in Cardiff"))
df2 <- data.frame(city = c("Manchester",
"Cardiff",
"London",
"Glasgow",
"Brighton",
"Nottingham"))
sapply(X = df1$Location, FUN = \(x){
out <- df2$city[sapply(X = df2$city, FUN = grepl, x = x, ignore.case = TRUE)]
out <- if(length(out) == 0) "-" else if(length(out) == 1) out else if(length(out) > 1) paste(out, collapse = ", ")
})
输出:
London/Liverpool London/Glasgow Manchester
"London" "London, Glasgow" "Manchester"
No I am based in Cardiff
"-" "Cardiff"
这可能不是最优雅的例子,但你可以尝试一下,我们会改进它。对于存在多个匹配项的情况,我让它显示所有匹配项并用逗号分隔它们。