代码之家  ›  专栏  ›  技术社区  ›  Makaroni

如何用R中的查找代码替换字符串列

  •  2
  • Makaroni  · 技术社区  · 5 年前

    假设我有一个dataframe或datatable,其中一行如下:

    a1; b: b1, b2, b3; c: c1, c2, c3; d: d1, d2, d3, d4
    

    以及一个查找表,其中包含映射这些字符串的代码。例如:

    string code
    a1     10
    b1     20
    b2     30
    b3     40
    c1     50
    c2     60
    ...
    

    我想要一个映射函数,它将此字符串映射到代码:

    10; b: 20, 30, 40; c: 50, 60, 70; d: 80, 90, 100
    

    注意,这个字符串的长度并不总是相同的。。。例如在一行中我可以有字符串 a d ,在其他 f

    编辑 :

    我们得到了上述情况的解决方案,但是假设我有一个这样的字符串:

    a; b: peter, joe smith, john smith; c: luke, james, john smith
    

    john smith 可以有两个不同的代码,具体取决于它是否属于 b c 类别?

    编辑2

       string     code
        a          10
        peter      20
        joe smith  30
        john smith 40
        luke       50
        james      60
        john smith 70
    ...
    

    最终的解决方案是:

    10; b: 20, 30, 40; c: 50, 60, 70
    

    编辑3 如前所述,我为下一期打开了一个新问题: How to replace repeated strings and space in-between with look-up codes in R

    3 回复  |  直到 5 年前
        1
  •  4
  •   akrun    5 年前

    我们可以利用 gsubfn

    library(gsubfn)
    gsubfn("([a-z]\\d+)", setNames(as.list(df1$code), df1$string), str1)
    #[1] "10; b: 20, 30, 40; c: 50, 60, 70; d: 80, 90, 100, 110"
    

    对于编辑后的版本

    gsubfn("(\\w+ ?\\w+?)",  setNames(as.list(df2$code), df2$string), str2)
    #[1] "a; b: 20, 30, 40; c: 50, 60, 40"
    

    数据

    str1 <- "a1; b: b1, b2, b3; c: c1, c2, c3; d: d1, d2, d3, d4"
    df1 <- structure(list(string = c("a1", "b1", "b2", "b3", "c1", "c2", 
     "c3", "d1", "d2", "d3", "d4"), code = c(10L, 20L, 30L, 40L, 50L, 
     60L, 70L, 80L, 90L, 100L, 110L)), class = "data.frame",
      row.names = c(NA, -11L))
    
    str2 <- "a; b: peter, joe smith, john smith; c: luke, james, john smith"
    
    df2 <- structure(list(string = c("a", "peter", "joe smith", "john smith", 
    "luke", "james", "john smith"), code = c(10L, 20L, 30L, 40L, 
    50L, 60L, 70L)), class = "data.frame", row.names = c(NA, -7L))
    
        2
  •  2
  •   lroha    5 年前

    一个更快的选择是 stringr::str_replace_all() :

    library(stringr)
    library(gsubfn)
    
    mystring <- "a1; b: b1, b2, b3; c: c1, c2, c3; d: d1, d2, d3, d4"
    mystrings <- rep(mystring, 10000)
    
    str_replace_all(mystrings, setNames(as.character(df$code), df$string))
    
    microbenchmark::microbenchmark(gsubfn = gsubfn("([a-z]\\d+)", setNames(as.list(df$code), df$string), mystrings),
                                   stringr = str_replace_all(mystrings, setNames(as.character(df$code), df$string)), check = "equal", times = 50)
    
    Unit: milliseconds
        expr        min         lq      mean     median         uq        max neval cld
      gsubfn 4846.19633 5584.54845 5923.5042 5939.49794 6261.29821 7479.04022    50   b
     stringr   29.01798   29.94274   31.6118   30.80002   31.72871   50.57533    50  a 
    
        3
  •  2
  •   ThomasIsCoding    5 年前

    下面是一些基本的R解。

    • 使用 Reduce
    res <- Reduce(function(x,k) gsub(df$string[k],df$code[k],x),
                  c(s,as.list(1:nrow(df))))
    

    > res
    [1] "10; b: 20, 30, 40; c: 50, 60, c3; d: d1, d2, d3, d4"
    
    • 方法2: 定义自定义递归函数 f
    f <- function(k) ifelse(k==0,s,gsub(df$string[k],df$code[k],f(k-1)))
    res <- f(nrow(df))
    

    如此

    >物件
    [1] “10;b:20、30、40;c:50、60、c3;d:d1d2d3d4

    数据

    s <- "a1; b: b1, b2, b3; c: c1, c2, c3; d: d1, d2, d3, d4"
    df <-structure(list(string = c("a1", "b1", "b2", "b3", "c1", "c2"), 
        code = c(10L, 20L, 30L, 40L, 50L, 60L)), class = "data.frame", row.names = c(NA, 
    -6L))