You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中实现地址标准化:将单门牌号替换为对应门牌号范围

R实现地址门牌号标准化(替换单个门牌号为对应范围)

需求说明:按街道分组,将属于某门牌号范围(如10-12)的单个门牌号(如10、12)替换为对应的范围字符串,不同街道的门牌号不混淆。

示例数据

data <- data.frame(
  street = c('smith st','smith st','smith st','smith st','smith st','park ave','park ave','park ave','george lane','george lane'),
  blg_no = c('10','10-12','36','12','13-15','27','12','27-29','34-38','15')
)

方法1:使用tidyverse(dplyr + stringr)

适合熟悉tidy语法的用户,代码可读性强:

library(dplyr)
library(stringr)

# 提取各街道的门牌号范围规则
range_rules <- data %>%
  filter(str_detect(blg_no, "-")) %>%
  separate(blg_no, into = c("start", "end"), sep = "-", convert = TRUE) %>%
  group_by(street) %>%
  mutate(range_str = paste(start, end, sep = "-"))

# 标准化门牌号
standardized_data <- data %>%
  mutate(row_id = row_number()) %>%  # 保留原行顺序
  left_join(range_rules, by = "street") %>%
  mutate(
    blg_no_num = as.numeric(blg_no),
    # 匹配单个门牌号对应的范围
    match_range = ifelse(
      !is.na(blg_no_num) & blg_no_num >= start & blg_no_num <= end,
      range_str,
      blg_no
    ),
    # 最终门牌号:范围号保留,单个号匹配后替换
    final_blg_no = ifelse(str_detect(blg_no, "-"), blg_no, match_range)
  ) %>%
  group_by(row_id) %>%
  mutate(final_blg_no = first(na.omit(final_blg_no))) %>%  # 取有效匹配结果
  ungroup() %>%
  select(street, blg_no = final_blg_no) %>%
  arrange(row_id) %>%
  select(-row_id)  # 移除行号列

# 查看结果
print(standardized_data)

方法2:使用data.table(高效处理大数据)

适合处理大规模数据集,运行速度快:

library(data.table)

setDT(data)

# 提取各街道的门牌号范围规则
range_dt <- data[grepl("-", blg_no), 
                 .(start = as.integer(strsplit(blg_no, "-")[[1]][1]),
                   end = as.integer(strsplit(blg_no, "-")[[1]][2]),
                   range_str = blg_no), 
                 by = .(street, blg_no)]
range_dt <- range_dt[, .(start, end, range_str), by = street]

# 非等值连接匹配范围
data[, blg_no_num := as.numeric(blg_no)]
standardized_dt <- data[range_dt, 
                        on = .(street, blg_no_num >= start, blg_no_num <= end),
                        matched_range := i.range_str]

# 生成最终标准化门牌号
standardized_dt[, final_blg_no := ifelse(grepl("-", blg_no), blg_no, 
                                         ifelse(!is.na(matched_range), matched_range, blg_no))]
standardized_dt <- standardized_dt[, .(street, blg_no = final_blg_no)]

# 查看结果
print(standardized_dt)

方法3:基础R实现(无需额外包)

不需要安装第三方包,适合纯基础R环境:

# 提取每个街道的门牌号范围
street_ranges <- lapply(split(data, data$street), function(df) {
  range_entries <- df$blg_no[grepl("-", df$blg_no)]
  if (length(range_entries) == 0) return(NULL)
  
  range_df <- do.call(rbind, strsplit(range_entries, "-")) %>%
    as.data.frame(stringsAsFactors = FALSE) %>%
    setNames(c("start", "end")) %>%
    mutate(
      start = as.integer(start),
      end = as.integer(end),
      range_str = range_entries
    )
  return(range_df)
})

# 逐个街道处理门牌号标准化
standardized_list <- lapply(names(street_ranges), function(street_name) {
  df <- data[data$street == street_name, ]
  ranges <- street_ranges[[street_name]]
  
  if (is.null(ranges)) return(df)
  
  df$blg_no_num <- as.numeric(df$blg_no)
  df$final_blg_no <- df$blg_no
  
  # 遍历每个范围,替换匹配的单个门牌号
  for (i in seq(nrow(ranges))) {
    match_mask <- !grepl("-", df$blg_no) & 
                  df$blg_no_num >= ranges$start[i] & 
                  df$blg_no_num <= ranges$end[i]
    df$final_blg_no[match_mask] <- ranges$range_str[i]
  }
  
  return(df[, c("street", "final_blg_no")] %>% setNames(c("street", "blg_no")))
})

# 合并结果并还原原顺序
standardized_data_base <- do.call(rbind, standardized_list)
standardized_data_base <- standardized_data_base[
  order(match(paste(standardized_data_base$street, standardized_data_base$blg_no), 
              paste(data$street, data$blg_no))), 
]

# 查看结果
print(standardized_data_base)

内容的提问来源于stack exchange,提问作者Mathew Carroll

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:02:05