在R中如何用refinr包对比两同类型列并规整字符串?
兄弟,我懂你合并数据框时被那些乱七八糟的字符串搞崩溃的感觉!国家名、市政名、姓名这类列简直是数据清洗的重灾区——大小写不一致、多字少字、拼写变体一堆,refinr作为OpenRefine的R移植版确实好用,但刚上手确实会懵怎么同时处理两个同类型列的字符串匹配,我给你捋个实用的方案,一步步来:
核心思路
把两个需要匹配的列的字符串先合并成一个大向量,让refinr基于所有可能的变体生成统一的规整结果,再通过映射表把规整后的值对应回原来的两个列,这样就能保证两列的字符串格式完全统一,合并时就不会因为微小差异匹配失败了。
具体操作示例
先给你整个贴近实际场景的示例代码,你可以直接套用到自己的数据上:
1. 加载包+构造示例数据
首先加载你已经用到的tidyverse和refinr,然后构造两个有字符串差异的示例数据框(模拟你要合并的两个数据源):
library(tidyverse) library(refinr) # 模拟两个需要合并的数据源,字符串存在各种变体 df1 <- tibble(id = 1:5, raw_city = c("New York", "new york city", "London", "los angeles", "Chicago")) df2 <- tibble(record_id = 1:5, official_city = c("New York City", "NYC", "london", "Los Angeles", "chicago IL"))
2. 合并两列字符串,统一规整
把两个列的所有字符串合并成一个向量,用refinr的核心函数处理——先key_collision_merge()处理完全匹配的变体(比如大小写差异),再n_gram_merge()处理近似匹配的变体(比如缩写、多字少字):
# 合并两个列的所有字符串到一个向量 combined_cities <- c(df1$raw_city, df2$official_city) # 用refinr规整字符串 cleaned_cities <- combined_cities %>% key_collision_merge() %>% n_gram_merge()
3. 创建原始字符串→规整字符串的映射表
这一步是关键,把每个原始字符串和对应的规整结果绑定起来,方便后续映射回原数据框:
city_mapping <- tibble(original = combined_cities, cleaned = cleaned_cities) %>% distinct() # 去重,保留唯一的映射关系
4. 把映射表应用到原数据框
分别给两个数据框添加上规整后的列,这样两列的格式就统一了:
# 给df1添加规整后的城市列 df1_cleaned <- df1 %>% left_join(city_mapping, by = c("raw_city" = "original")) %>% rename(cleaned_city = cleaned) # 给df2添加规整后的城市列 df2_cleaned <- df2 %>% left_join(city_mapping, by = c("official_city" = "original")) %>% rename(cleaned_city = cleaned)
5. 轻松合并数据框
现在两个数据框都有了统一的cleaned_city列,直接用这个列合并就不会有匹配问题了:
# 合并两个规整后的数据框 merged_df <- df1_cleaned %>% inner_join(df2_cleaned, by = "cleaned_city")
进阶优化:预处理字符串
如果你的数据有更多特殊字符(比如标点、后缀),可以先做预处理,比如转小写、去除无关字符,再用refinr处理,效果会更好:
# 自定义预处理函数:转小写、去除非字母数字/空格、压缩多余空格 preprocess_str <- function(x) { x %>% str_to_lower() %>% str_remove_all("[^a-z0-9 ]") %>% str_squish() } # 预处理后再规整 combined_cities_processed <- combined_cities %>% preprocess_str() cleaned_cities_processed <- combined_cities_processed %>% key_collision_merge() %>% n_gram_merge() # 更新映射表,保留原始字符串和最终规整结果的对应 city_mapping_processed <- tibble(original = combined_cities, cleaned = cleaned_cities_processed) %>% distinct(original, .keep_all = TRUE)
这样处理后,不管是"Chicago"还是"chicago IL",都会被规整成一致的格式,合并起来就顺畅多了!
内容的提问来源于stack exchange,提问作者Tdebeus

