【问题标题】:how can I extract numbers from a string in R?如何从 R 中的字符串中提取数字?
【发布时间】:2017-02-06 22:54:26
【问题描述】:
names(score)
 [1] "(Intercept)"              "aado2_calc(20,180]"       "aado2_calc(360,460]"     
 [4] "aado2_calc(460,629]"      "albumin[1,1.8]"           "albumin(1.8,2.2]"        
 [7] "albumin(2.2,2.8]"         "aniongap(15,18]"          "aniongap(18,20]"         
[10] "aniongap(20,22]"          "aniongap(22,25]"          "aniongap(25,49]"    

我想提取括号内的两个数字(括号外的数字不需要)并且有“(”或“[”。第一个数字将分配给对象“low”,第二个数字将分配给“high” ”。

【问题讨论】:

  • 这是什么语言?
  • 对不起,这是R
  • strsplit by parentheses的可能重复
  • 看起来最好使用正则表达式 more info。我在想/[A-Za-z_][A-Za-z0-9_]*\(([-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?,[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?\]$/又名<identifier> '(' <float>, <float> ']'
  • 为了将来参考,你不应该需要标题中的“in R”; tilz0R 的评论对于与 R 相关的东西是不必要的和不明智的,可能看不到 [r] 标签。 (对于 R 的东西,标签通常就足够了。对于其他编程语言可能不是这样。)

标签: r string numbers stringr


【解决方案1】:

您可以使用readr 包和函数parse_number 以方便使用。要获得更多功能,您需要使用 r 中的基本正则表达式函数,或者像 stringi 这样的包。

【讨论】:

    【解决方案2】:

    就像@jake-kaupp 说的那样——使用stringi :) 正如你所看到的,stringi 解决方案更短、更容易理解并且速度更快——高达 30 倍!

    简答:

    arr <- stri_extract_all_regex(x, "(?<=[\\[\\(,])[0-9.]+(?=[\\]\\),])", simplify = NA)
    data.frame(low = as.numeric(arr[,1]), high = as.numeric(arr[,2]))
    

    长答案:

    require(stringi)
    require(microbenchmark)
    
    grepFun <- function(x){
      mat <- regmatches(x,
                    gregexpr("(?<=[\\[\\(,])[0-9.]+(?=[\\]\\),])", x, perl = TRUE))
      newnames <- lapply(mat, function(m) {
        if (! length(m)) return(list(low = NA, high = NA))
          setNames(as.list(as.numeric(m)), nm = c("low", "high"))
      })
      do.call(rbind.data.frame, newnames)
    }
    
    striFun <- function(x){
      arr <- stri_extract_all_regex(x, "(?<=[\\[\\(,])[0-9.]+(?=[\\]\\),])", simplify = NA)
      data.frame(low = as.numeric(arr[,1]), high = as.numeric(arr[,2]))
    }
    
    # 两个函数的作用相同 grepFun(分数名称) 低高 1 无 无 2 20.0 180.0 3 360.0 460.0 4 460.0 629.0 ... 12 25.0 49.0 striFun(乐谱) 低高 1 无 无 2 20.0 180.0 3 360.0 460.0 4 460.0 629.0 ... 12 25.0 49.0
    # generating more complicated vector 
    n <- 10000
    x <- stri_paste(stri_rand_strings(n, length = 1:10), sample(c("(","["),n,TRUE),  
      sample(1000,n,TRUE), ",", sample(1000,n,TRUE),    sample(c(")","]"), n, TRUE))
    head(x) # check first elements
    [1] "O[68,434]"      "Ql[783,151)"    "Zk0(773,60)"    "ETfV(446,518]"  "Xixbr(576,855)" "G6QnHu(92,955)"
    
    #short test 使用新数据 grepFun(x[1:6]) 低高 1 68 434 2 783 151 3 773 60 4 446 518 5 576 855 6 92 955 striFun(x[1:6]) 低高 1 68 434 2 783 151 3 773 60 4 446 518 5 576 855 6 92 955 #和一些基准来证明性能 微基准(grepFun(x),striFun(x)) 单位:毫秒 expr min lq mean 中位数 uq max neval grepFun(x) 330.27733 366.09306 416.56330 406.08914 465.29829 568.15250 100 striFun(x) 11.57449 11.97825 13.38157 12.46927 13.67699 25.97455 100

    【讨论】:

      【解决方案3】:
      scorenames <- c(
        "(Intercept)"              ,"aado2_calc(20,180]"       ,"aado2_calc(360,460]"     
       ,"aado2_calc(460,629]"      ,"albumin[1,1.8]"           ,"albumin(1.8,2.2]"        
       ,"albumin(2.2,2.8]"         ,"aniongap(15,18]"          ,"aniongap(18,20]"         
       ,"aniongap(20,22]"          ,"aniongap(22,25]"          ,"aniongap(25,49]"
      )
      

      第一步可能是提取“parens”分隔符中的所有内容(包括()[] 和逗号,)。

      mat <- regmatches(scorenames,
                        gregexpr("(?<=[\\[\\(,])[0-9.]+(?=[\\]\\),])", scorenames, perl = TRUE))
      str(mat)
      # List of 12
      #  $ : chr(0) 
      #  $ : chr [1:2] "20" "180"
      #  $ : chr [1:2] "360" "460"
      #  $ : chr [1:2] "460" "629"
      #  $ : chr [1:2] "1" "1.8"
      #  $ : chr [1:2] "1.8" "2.2"
      #  $ : chr [1:2] "2.2" "2.8"
      #  $ : chr [1:2] "15" "18"
      #  $ : chr [1:2] "18" "20"
      #  $ : chr [1:2] "20" "22"
      #  $ : chr [1:2] "22" "25"
      #  $ : chr [1:2] "25" "49"
      

      从这里,我们可以看到(1)第一个是有问题的(毫不奇怪,你需要在这里弄清楚你想要什么),以及(2)其余的看起来都差不多。

      这是处理此列表的一种粗略方法。这是非常信任和幼稚的...您可能应该添加检查以确保列表的长度为 2,确保所有内容都正确转换(可能在 tryCatch 中)等等。

      newnames <- lapply(mat, function(m) {
        if (! length(m)) return(list(low = NA, high = NA))
        setNames(as.list(as.numeric(m)), nm = c("low", "high"))
      })
      str(newnames)
      # List of 12
      #  $ :List of 2
      #   ..$ low : logi NA
      #   ..$ high: logi NA
      #  $ :List of 2
      #   ..$ low : num 20
      #   ..$ high: num 180
      #  $ :List of 2
      #   ..$ low : num 360
      #   ..$ high: num 460
      # ...snip...
      

      你可以把它变成一个data.frame:

      head(do.call(rbind.data.frame, newnames))
      #     low  high
      # 1    NA    NA
      # 2  20.0 180.0
      # 3 360.0 460.0
      # 4 460.0 629.0
      # 5   1.0   1.8
      # 6   1.8   2.2
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-17
        • 2013-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多