【问题标题】:change the values in a column of a dataframe using another dataframe that contains key pairs使用包含键对的另一个数据框更改数据框列中的值
【发布时间】:2021-10-24 21:20:59
【问题描述】:

我有以下示例 df

df <- data.frame(old=c("412oldname1","32oldname132","oldname141","132oldname2","oldname3","oldname4","oldname5"))

        old
1   412oldname1
2   32oldname132
3   oldname141
4   132oldname2
5   oldname3
6   oldname4
7   oldname5

我想使用 grepl 提取行并替换。

keypairs <- data.frame(old=c("oldname1","oldname2"),new=c("newname1","newname2"))

       old      new
1 oldname1 newname1
2 oldname2 newname2

所需的数据框是:

        old
1   newname1
2   newname1
3   newname1
4   newname2

理想情况下,我可以用模式替换 grepl 的输出,然后使用 left_join 并选择 new 列。

到目前为止,我有:

df %>% filter(grepl(keypairs$old,collapse="|"))
# still trying to figure out what to do at this step
%>% left_join(keypairs) %>% select(new)

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    可能有更有效的方法,但我以前使用过类似的方法。

    library(dplyr)
    library(purrr)
    library(stringr)
    
    str_grab <- function(string, pattern) pattern[str_which(string, coll(pattern))[1]]
    

    使用它来提取标准化名称。

    df %>% 
      mutate(clean = map_chr(old, str_grab, keypairs$old)) %>% 
      left_join(keypairs, by = c(clean = "old"))
    #            old    clean      new
    # 1  412oldname1 oldname1 newname1
    # 2 32oldname132 oldname1 newname1
    # 3   oldname141 oldname1 newname1
    # 4  132oldname2 oldname2 newname2
    # 5     oldname3     <NA>     <NA>
    # 6     oldname4     <NA>     <NA>
    # 7     oldname5     <NA>     <NA>
    

    如果您只想保留匹配的内容,请使用 inner_join() 而不是 left_join()。然后您可以使用基本的dplyr 命令重命名并选择您想要的列。

    df %>% 
      mutate(clean = map_chr(old, str_grab, keypairs$old)) %>% 
      inner_join(keypairs, by = c(clean = "old")) %>% 
      select(old = new)
    #        old
    # 1 newname1
    # 2 newname1
    # 3 newname1
    # 4 newname2
    

    正如怀疑的那样,有一种更有效的方法。以下是建议方法的一些基准。

    Martin Gal 提供的方法在执行时间和代码行数上要高效得多。

    Unit: milliseconds
                expr     min       lq      mean   median       uq     max neval
       method_adam()  7.1371  7.68660  8.706662  8.03725  8.54810 16.5197   100
     method_martin()  1.1090  1.21125  1.464750  1.29145  1.42950  7.1925   100
      method_akrun() 25.4143 26.72945 29.400662 27.64135 32.21115 50.5500   100
    

    【讨论】:

      【解决方案2】:

      类似亚当的方法:

      library(dplyr)
      library(stringr)
      library(tibble)
      # or simply
      # library(tidyverse) 
      
      df %>% 
        mutate(new = deframe(keypairs)[str_extract(old, paste(keypairs$old, collapse = "|"))])
      

      返回

                 old      new
      1  412oldname1 newname1
      2 32oldname132 newname1
      3   oldname141 newname1
      4  132oldname2 newname2
      5     oldname3     <NA>
      6     oldname4     <NA>
      7     oldname5     <NA>
      

      这里发生了什么?

      • deframe(keypairs) 创建一个“查找”向量。例如:如果我们将“oldname1”放入其中,则返回“newname1”。
      • str_extract 提取查找的输入。我们在old 列中搜索正确的“旧名称”。

      【讨论】:

      • 这无疑是一种更有效的方式。我跑了一个基准只是为了好玩,这运行得更快。
      【解决方案3】:

      我们可以使用fuzzyjoin

      library(fuzzyjoin)
      regex_left_join(df, keypairs, by = 'old') %>% 
           transmute(old = old.x, new)
                 old      new
      1  412oldname1 newname1
      2 32oldname132 newname1
      3   oldname141 newname1
      4  132oldname2 newname2
      5     oldname3     <NA>
      6     oldname4     <NA>
      7     oldname5     <NA>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-14
        相关资源
        最近更新 更多