【问题标题】:Standardize the City Name in R标准化 R 中的城市名称
【发布时间】:2021-07-10 03:24:34
【问题描述】:

我是 R 和编码领域的新手,请原谅我在这里拼错了一些或更多行话 (cmiiw)。

我面临着在数据框中清理城市名称的挑战。

尝试使用GetCloseMatchesstrdist_inner_join(我相信用fuzzywuzzy)和dplyr 风格,但仍然不能满足我的需求。

第一次尝试:

vec3 = unlist(world.cities$name)

str1 = c('Jakarta Utara')

GetCloseMatches(string = str1, sequence_strings = vec3, n = 1L, cutoff = 0.6)

但它每次只能“翻译”一个城市,你知道如何让它对所有数据框重复吗? for 循环还是函数?

第二次尝试:

df2 <- df[1:10,] %>%

stringdist_left_join(world.cities, by = c(cust_city = "name"), max_dist = 1)

它显示了大部分城市,但缺少“Jakarta Utara”

我正在使用两个待检查城市的数据库/数据框(cmiiw)(如果您看到右侧的“查找”表,它有数百个城市名称,而不仅仅是6个),首先是SHP我强化的文件,第二个是 world.cities$name,两者都做得很好,但不知何故,它一次只出现一个城市。即:如果我使用 SHP 文件,则会出现 Jakarta Utara 但不会出现 Karawang,反之亦然。

我的目标是将左边的词替换为右边的词(1到2)

左>右

加拉旺 - 到加拉旺

雅加达至雅加达

雅加达到雅加达等

你知道最有效的方法吗?

非常感谢您的帮助!

问候

【问题讨论】:

  • 嗯,也许你可以使用Vectorize对函数进行矢量化(我发了一篇关于它的帖子here)?
  • 这里有几个解决方案。如果您的问题由我们中的一个人回答。请通过单击对您最有帮助的答案左侧的复选标记来关闭您的问题。谢谢。

标签: r city stringdist fuzzyjoin


【解决方案1】:

您可以使用mapstr_detect。请让我知道它是否有效。

library(tidyverse)

df %>%
  mutate(City = map(City, ~df1$City[str_detect(.x,df1$City)])) %>% 
  unnest ()

输出:

# A tibble: 5 x 3
  Name      Qty City             
  <chr>   <dbl> <chr>            
1 Alex       10 Jakarta          
2 Bambang     5 Jakarta          
3 Charlie    15 Batam            
4 Delta      10 Tangerang Selatan
5 Emily       5 Jakarta   

数据:

df <- tribble(
~Name, ~Qty, ~City,
"Alex", 10, "Jakarta Barat",
"Bambang", 5, "Jakarta",
"Charlie", 15, "Nagoya Batam",
"Delta", 10, "Bintaro Tangerang Selatan",
"Emily", 5, "Tendean Jakarta Selatan 11750"
)


df1 <- tribble(
~City,
"Jakarta",
"Bandung",
"Batam",
"Surabay",
"Tangerang Selatan"
)

【讨论】:

    【解决方案2】:

    如果我正确理解您的问题,您希望根据已知城市名称列表解析 City 变量,并将较长的 City 名称替换为已知城市名称列表中的版本。正确的?如果是,那么希望这种方法对你有用(不需要额外的包):

    # replicate your example data 1
    d <-data.frame("No"=c(1,2,3,4,5),"Name"=c("Alex","Bambang","Charlie","Delta","Emily"),"Qty"=c(10,5,15,10,5),"City"=c("Jakarta Barat","Jakarta","Nagoya Batam","Bintaro Tangerang Selatan","Tendean Jakarta Selatan 11750"))
    # replicate your vector of known city names
    city_list <- c("Jakarta","Bandung","Batam","Surabaya","Tangerang Selatan")
    
    # making a new placeholder variable to store the matched city names.
    d$City_fix <- NA
    
    # use a for loop, ifelse(), and grepl() to go through the vector of known cities, and replace the city name when a match is found.
    for (i in 1:length(city_list)){
      d$City_fix <- ifelse(grepl(city_list[i], d$City), city_list[i], d$City_fix)
    }
    
    # view results
    d
    
      No    Name Qty                          City          City_fix
    1  1    Alex  10                 Jakarta Barat           Jakarta
    2  2 Bambang   5                       Jakarta           Jakarta
    3  3 Charlie  15                  Nagoya Batam             Batam
    4  4   Delta  10     Bintaro Tangerang Selatan Tangerang Selatan
    5  5   Emily   5 Tendean Jakarta Selatan 11750           Jakarta
    

    使用已知城市的向量将允许您在循环中选择任意数量的城市。如果您有两个城市可能共享同一城市名称的一部分,请小心,例如“大城市”和“新大城市”。

    如果您在源数据框或城市列表中的城市名称具有不同的大小写字母,您需要先修复该名称(例如,来自 base R 的 tolower() 或来自 stringr 包的 str_to_title())。

    上述解决方案还要求数据框中的城市名称拼写正确。如果您有拼写错误,例如Jakerta 而不是 Jakarta,则需要更复杂的解决方案。

    (已编辑以包括提及能力以拥有一长串已知城市名称)

    【讨论】:

    • 嗨,Shawn,感谢您的回复,我已经测试了您的代码,用于某行 df 并且效果很好!首先,我使用 world.cities 并将其过滤为仅出现一个国家/地区,然后我取消列出 world.cities$name,将其放在您的 For-Loop 代码中,瞧!我将确保它在整体数据上表现良好。从现在开始,非常感谢您! :D
    • 请问city_list[i]中[i]的含义/目的?
    • 很抱歉,回复晚了——现在才赶上您的后续问题。 for 循环中的 i 指的是索引,然后它将获取指定循环中的第一个数字值,并在每次通过循环时向上计数。在本例中,指定的循环为 1:length(city_list),在本例中为 1:5,i 将是该循环的索引值。例如,对于 i 的每个实例,第一遍 i=1 使得: d$City_fix
    【解决方案3】:

    您可以使用dplyr 中的case_when 根据您的要求映射您的城市

    library(dplyr) # for mutate and case_when
    
    # demo data
    data_input <- data.frame(num = c(1,2,3,4,5), 
                             city = c("Jakarta Barat", "Jakarta", "Nagoya Batam", 
                                      "Bintaro Tangerang Seltan", "Tandean Jakarta Selatan"), 
                             stringsAsFactors = FALSE)
    
    # Use case_when to mapp according to mapping table
    output_reqd <- data_input %>% 
      mutate(new_city = case_when(grepl(pattern = "Jakarta", x = city) ~ "Jakarta",
                                  grepl(pattern = "Batam", x = city) ~ "Batam",
                                  grepl(pattern = "Tangerang Seltan", x = city) ~ "Tangerang Seltan",
                                  TRUE ~ city)
             )
    

    【讨论】:

    • 感谢您的回复!如果 List 表多达数百个城市怎么办? (查找表中不仅有 6 个城市)
    • @rgoei 查看我的解决方案,其中包含单个城市向量并使用 for 循环。 mutate 和 case_when 也可以采用类似的解决方案。
    【解决方案4】:

    我已经更新了答案,使用maps::world.cities 匹配来选择更多国家/地区。

    library(tidyverse)
    library(maps)
    library(fuzzyjoin)
    
    wc <- world.cities %>% 
      as_tibble()
    
    table <- data.frame(
      customers = seq(1, 5, 1),
      city = c(
        "Jakarta Barat",
        "Jakarta",
        "Nagoya Batam",
        "Bintaro Tangerang Selatan",
        "Tendean Jakarta Selatan 11750"
      )) %>% 
      as_tibble() %>% 
      mutate(country = "Indonesia")
    
    table %>% 
      regex_inner_join(wc, 
                       by = c(city = "name",
                              country = "country.etc"))
    

    我已将国家/地区列添加到我的数据中,以使连接更加准确。这可以扩展到数百个城市。

    【讨论】:

    • 感谢您的回复!如果 List 表多达数百个城市怎么办? (查找表中不仅有 6 个城市)
    • 我已经更新了答案,使其适用于数百个城市/国家。
    猜你喜欢
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多