【问题标题】:Efficient way to add numbers to alphanumeric strings in R在R中将数字添加到字母数字字符串的有效方法
【发布时间】:2019-05-08 15:26:44
【问题描述】:

我有一个data.frame,其 id 由字母数字字符序列组成(例如,id = c(A001, A002, B013))。我在stringr 或stirngi 下寻找一个简单的函数,它可以很容易地用这个字符串做数学运算(id + 1 应该返回c(A002, A003, B014))。

我制作了一个自定义函数来解决这个问题,但是我觉得必须有更好/更有效/包内的方法来实现这一点。

str_add_n <- function(df, string, n, width=3){

  string <- enquo(string)

  ## split the string using pattern
df <-  df %>%
    separate(!!string,
             into = c("text", "num"), 
             sep = "(?<=[A-Za-z])(?=[0-9])",
             remove=FALSE
    ) %>%
    mutate(num = as.numeric(num),
           num = num + n,
           num = stringr::str_pad(as.character(num),
                                  width = width,
                                  side = "left",
                                  pad = 0 
                                  )
           ) %>%
    unite(next_string, text:num, sep = "")


return(df)  
}

我们来做个玩具df

df <- data.frame(id = c("A001", "A002", "B013"))
str_add_n(df, id, 1)
    id next_string
1 A001        A002
2 A002        A003
3 B013        B014

再次,这可行,我想知道是否有更好的方法来做到这一点,欢迎所有调整!

更新

根据建议的答案,我运行了一些基准测试,看起来两者都非常接近,我倾向于str_add_n_2(我更改了名称以便能够同时运行两者,并接受了x&lt;-as.character(x) 的建议)

microbenchmark::microbenchmark(question = str_add_n(df, id, 1),
 answer = df %>% mutate_at(vars(id), funs(str_add_n_2(., 1))),
 string_add = df %>% mutate_at(vars(id), funs(string_add(as.character(.)))))

产量

Unit: milliseconds
       expr      min       lq     mean   median       uq
   question 4.312094 4.448391 4.695276 4.570860 4.755748
     answer 2.932146 3.017874 3.191262 3.117627 3.240688
 string_add 3.388442 3.466466 3.699363 3.534416 3.682762
      max neval cld
 10.29253   100   c
  8.24967   100 a  
  9.05441   100  b 

欢迎进行更多调整!

【问题讨论】:

    标签: r string tidyr stringr


    【解决方案1】:

    这是gsubfn的一种方式

    id <- c("A001", "A002", "B013")
    
    library(gsubfn)
    gsubfn("([0-9]+)", function(x) sprintf("%03.0f", as.numeric(x) + 1), id)
    #[1] "A002" "A003" "B014"
    

    你可以把它变成一个函数

    string_add <- function(string, add = 1, width = 3) {
      gsubfn::gsubfn("([0-9]+)", function(x) sprintf(paste0("%0", width, ".0f"), as.numeric(x) + add), string)
    }
    
    string_add(id, add = 10, width = 5)
    #"A00011" "A00012" "B00023"
    

    【讨论】:

      【解决方案2】:

      我建议根据字符串的向量定义函数更容易,而不是硬编码来查找框架中的列;对于后者,您始终可以使用 mutate_at(vars(id,...), funs(str_add_n)) 之类的内容。

      str_add_n <- function(x, n = 1L) {
        gr <- gregexpr("\\d+", x)
        reg <- regmatches(x, gr)
        widths <- nchar(reg)
        regmatches(x, gr) <- sprintf(paste0("%0", widths, "d"), as.integer(reg) + n)
        x
      }
      
      vec <- c("A001", "A002", "B013")
      str_add_n(vec)
      # [1] "A002" "A003" "B014"
      

      如果在一个框架中:

      df <- data.frame(id = c("A001", "A002", "B013"), x = 1:3,
                       stringsAsFactors = FALSE)
      library(dplyr)
      df %>%
        mutate_at(vars(id), funs(str_add_n(., 3)))
      #     id x
      # 1 A004 1
      # 2 A005 2
      # 3 B016 3
      

      警告:这需要真正的character,而不是factor ...一种可能的防御策略可能是在函数定义中添加x &lt;- as.character(x)。

      【讨论】:

        猜你喜欢
        • 2015-04-26
        • 1970-01-01
        • 2021-10-28
        • 1970-01-01
        • 1970-01-01
        • 2021-07-02
        • 1970-01-01
        • 1970-01-01
        • 2020-10-03
        相关资源
        最近更新 更多