如何基于Species列前两词匹配合并两个大数据量DataFrame?
基于物种学名前两个单词合并大数据量DataFrame的实现方法
我有两个DataFrame需要基于Species列合并:
- DataFrame 1的
Species列仅包含物种名称的前两个单词 - DataFrame 2的
Species列是带命名人信息的完整学名
要求仅通过Species列的前两个单词进行匹配(例如Themeda triandra与Themeda triandra Forssk.视为匹配),需处理大数据量(df1共32,931行,df2共16,185行),无匹配项标记为NA。
示例数据
DataFrame 1:
| Species |
|---|
| Themeda australis |
| Themeda avenacea |
| Themeda quadrivalvis |
| Themeda triandra |
| Lomandra juncea |
| Lomandra longifolia |
DataFrame 2:
| Species | Common_name |
|---|---|
| Themeda australis (R.Br.) Stapf | Kangaroo grass |
| Themeda avenacea (F.Muell.) Lugger | Native oat |
| Themeda quadrivalvis (L.) Kuntze. | Grader grass |
| Themeda triandra Forssk. | Kangaroo grass |
| Lomandra juncea (F.Muell.) Ewart | Desert Mat-rush |
| Lomandra longifolia Labill. | Spiny-headed Mat-rush |
数据定义代码:
df1 <- data.frame(Species = c( "Themeda australis", "Themeda avenacea", "Themeda quadrivalvis", "Themeda triandra", "Lomandra juncea", "Lomandra longifolia" )) df2 <- data.frame(Species = c( "Themeda australis (R.Br.) Stapf", "Themeda avenacea (F.Muell.) Lugger", "Themeda quadrivalvis (L.) Kuntze.", "Themeda triandra Forssk.", "Lomandra juncea (F.Muell.) Ewart", "Lomandra longifolia Labill." ), Common_name = c( "Kangaroo grass", "Native oat", "Grader grass", "Kangaroo grass", "Desert Mat-rush", "Spiny-headed Mat-rush" ))
期望输出
| Species | Common_name |
|---|---|
| Themeda australis | Kangaroo grass |
| Themeda avenacea | Native oat |
| Themeda quadrivalvis | Grader grass |
| Themeda triandra | Kangaroo grass |
| Lomandra juncea | Desert Mat-rush |
| Lomandra longifolia | Spiny-headed Mat-rush |
原尝试代码(未得到理想结果)
output <- df1 %>% fuzzy_inner_join(df2, by = "Species", match_fun = str_detect)
解决方案
问题原因
原代码的str_detect匹配逻辑颠倒:fuzzy_inner_join默认用match_fun(left_col, right_col),即检查df1的Species是否包含df2的Species,这显然不符合需求;更关键的是,模糊匹配对大数据量效率极低,推荐先提取匹配键再做精确匹配。
方法1:提取匹配键后精确匹配(高效,适合大数据量)
给df2提取Species列的前两个单词作为匹配键,再用left_join完成合并,无匹配项自动标记为NA:
library(tidyverse) # 处理df2,提取前两个单词作为匹配键 df2_processed <- df2 %>% mutate(match_key = str_extract(Species, "^\\w+ \\w+")) # 合并并整理列 output <- df1 %>% left_join(df2_processed, by = c("Species" = "match_key")) %>% select(Species = Species.x, Common_name)
方法2:Base R实现(无需加载tidyverse)
# 给df2生成匹配键 df2$match_key <- sapply(strsplit(df2$Species, " "), function(x) paste(x[1:2], collapse = " ")) # 合并并筛选列 output <- merge(df1, df2, by.x = "Species", by.y = "match_key", all.x = TRUE)[, c("Species", "Common_name")]
方法3:修正模糊匹配(仅适合小数据量)
如果一定要用模糊匹配,需调整match_fun的参数顺序,但大数据量下不推荐:
library(fuzzyjoin) library(stringr) output <- df1 %>% fuzzy_left_join(df2, by = "Species", match_fun = function(x, y) str_detect(y, x)) %>% select(Species = Species.x, Common_name)
以上方法均可得到符合期望的输出,其中方法1和2效率更高,适合处理你的大数据量需求。
内容的提问来源于stack exchange,提问作者user22444391
相关产品推荐
相关产品推荐

