【问题标题】:How to very efficiently extract specific pattern from characters?如何非常有效地从字符中提取特定模式?
【发布时间】:2015-01-06 13:42:50
【问题描述】:

我有这样的大数据:

> Data[1:7,1]
[1] mature=hsa-miR-5087|mir_Family=-|Gene=OR4F5        
[2] mature=hsa-miR-26a-1-3p|mir_Family=mir-26|Gene=OR4F9
[3] mature=hsa-miR-448|mir_Family=mir-448|Gene=OR4F5   
[4] mature=hsa-miR-659-3p|mir_Family=-|Gene=OR4F5      
[5] mature=hsa-miR-5197-3p|mir_Family=-|Gene=OR4F5     
[6] mature=hsa-miR-5093|mir_Family=-|Gene=OR4F5        
[7] mature=hsa-miR-650|mir_Family=mir-650|Gene=OR4F5

我想要做的是,在每一行中,我想选择单词 ma​​ture= 之后的名称以及 Gene= 之后的单词,然后对它们进行命名和

一起
paste(a,b, sep="-")

例如,前两行的预期输出如下:

hsa-miR-5087-OR4F5
hsa-miR-26a-1-3p-OR4F9

所以,最终的实现是这样的:

for(i in 1:nrow(Data)){
    Data[i,3] <- sub("mature=([^|]*).*Gene=(.*)", "\\1-\\2", Data[i,1])
    Name <- strsplit(as.vector(Data[i,2]),"\\|")[[1]][2]
    Data[i,4] <- as.numeric(sub("pvalue=","",Name))
    print(i)
}

效果很好,但速度很慢。 Data 的大小非常大,它有 200,000,000 行。这个实现非常慢。我怎样才能加快速度?

【问题讨论】:

  • 我们没有Data,所以在提出这样的问题时,最好显示这样的数据:x &lt;- Data[1:7, 1]; dput(x)
  • 您的编辑使这有点像一个移动的目标——最初并不清楚您是否需要一个计算效率高的解决方案。我鼓励您针对以下提供的所有答案发布您自己对这个问题的答案,该答案显示了相当大的数据集的基准(例如,在数据集的前 100,000 行上尝试),遵循this question 的答案中给出的格式。
  • 您还可以查看用于快速字符串处理的stringi package,以及data.table 和/或dplyr

标签: regex r


【解决方案1】:

如果您可以保证格式与您指定的完全相同,那么正则表达式可以捕获(由下面的括号表示)从等号到管道符号,从 Gene= 到末尾的所有内容,然后粘贴它们加上一个减号:

sub("mature=([^|]*).*Gene=(.*)", "\\1-\\2", Data[,1])

【讨论】:

    【解决方案2】:

    另一种选择是使用read.table= 作为分隔符,然后粘贴两列:

    res = read.table(text=txt,sep='=')
    paste(sub('[|].*','',res$V2),            ## get rid from last part here
          sub('^ +| +$','',res$V4),sep='-')  ## remove extra spaces 
    
    [1] "hsa-miR-5087-OR4F5"     "hsa-miR-26a-1-3p-OR4F9" "hsa-miR-448-OR4F5"      "hsa-miR-659-3p-OR4F5"  
    [5] "hsa-miR-5197-3p-OR4F5"  "hsa-miR-5093-OR4F5"     "hsa-miR-650-OR4F5"   
    

    【讨论】:

      【解决方案3】:

      已经给出的简单sub 解决方案看起来相当不错,但以防万一,这里有一些其他方法:

      1) read.patterngsubfn package 中使用read.pattern,我们可以将数据解析成data.frame。这种中间形式DF 然后可以通过多种方式进行操作。在这种情况下,我们使用paste 的方式与问题基本相同:

      library(gsubfn)
      DF <- read.pattern(text = Data[, 1], pattern = "(\\w+)=([^|]*)")
      paste(DF$V2, DF$V6, sep = "-")
      

      给予:

      [1] "hsa-miR-5087-OR4F5"     "hsa-miR-26a-1-3p-OR4F9" "hsa-miR-448-OR4F5"     
      [4] "hsa-miR-659-3p-OR4F5"   "hsa-miR-5197-3p-OR4F5"  "hsa-miR-5093-OR4F5"    
      [7] "hsa-miR-650-OR4F5"   
      

      生成的中间数据帧DF 如下所示:

      > DF
            V1               V2         V3      V4   V5    V6
      1 mature     hsa-miR-5087 mir_Family       - Gene OR4F5
      2 mature hsa-miR-26a-1-3p mir_Family  mir-26 Gene OR4F9
      3 mature      hsa-miR-448 mir_Family mir-448 Gene OR4F5
      4 mature   hsa-miR-659-3p mir_Family       - Gene OR4F5
      5 mature  hsa-miR-5197-3p mir_Family       - Gene OR4F5
      6 mature     hsa-miR-5093 mir_Family       - Gene OR4F5
      7 mature      hsa-miR-650 mir_Family mir-650 Gene OR4F5
      

      这是我们使用的正则表达式的可视化:

      (\w+)=([^|]*)
      

      Debuggex Demo

      1a) 名称 我们可以通过分别读取三列数据和三个名称来使DF 看起来更好。这也改进了paste 语句:

      DF <- read.pattern(text = Data[, 1], pattern = "=([^|]*)")
      names(DF) <- unlist(read.pattern(text = Data[1,1], pattern = "(\\w+)=", as.is = TRUE))
      
      paste(DF$mature, DF$Gene, sep = "-") # same answer as above
      

      生成的此部分中的DF 如下所示。它有 3 列而不是 6 列,其余列用于确定适当的列名:

      > DF
                  mature mir_Family  Gene
      1     hsa-miR-5087          - OR4F5
      2 hsa-miR-26a-1-3p     mir-26 OR4F9
      3      hsa-miR-448    mir-448 OR4F5
      4   hsa-miR-659-3p          - OR4F5
      5  hsa-miR-5197-3p          - OR4F5
      6     hsa-miR-5093          - OR4F5
      7      hsa-miR-650    mir-650 OR4F5
      

      2)straplyc

      使用相同包的另一种方法。这将提取在 = 之后且不包含 | 的字段。产生一个列表。然后,我们将第一个和第三个字段粘贴在一起,对该列表进行 sapply:

      sapply(strapplyc(Data[, 1], "=([^|]*)"), function(x) paste(x[1], x[3], sep = "-"))
      

      给出相同的结果。

      这里是使用的正则表达式的可视化:

      =([^|]*)
      

      Debuggex Demo

      【讨论】:

        【解决方案4】:

        这是一种方法:

        Data <- readLines(n = 7)
        mature=hsa-miR-5087|mir_Family=-|Gene=OR4F5        
        mature=hsa-miR-26a-1-3p|mir_Family=mir-26|Gene=OR4F9
        mature=hsa-miR-448|mir_Family=mir-448|Gene=OR4F5   
        mature=hsa-miR-659-3p|mir_Family=-|Gene=OR4F5      
        mature=hsa-miR-5197-3p|mir_Family=-|Gene=OR4F5     
        mature=hsa-miR-5093|mir_Family=-|Gene=OR4F5        
        mature=hsa-miR-650|mir_Family=mir-650|Gene=OR4F5
        df <- read.table(sep = "|", text = Data, stringsAsFactors = FALSE)
        l <- lapply(df, strsplit, "=")
        trim <- function(x) gsub("^\\s*|\\s*$", "", x)
        paste(trim(sapply(l[[1]], "[", 2)), trim(sapply(l[[3]], "[", 2)), sep = "-")
        # [1] "hsa-miR-5087-OR4F5"     "hsa-miR-26a-1-3p-OR4F9" "hsa-miR-448-OR4F5"      "hsa-miR-659-3p-OR4F5"   "hsa-miR-5197-3p-OR4F5"  "hsa-miR-5093-OR4F5"    
        # [7] "hsa-miR-650-OR4F5"
        

        【讨论】:

          【解决方案5】:

          也许不是更优雅,但你可以试试:

          sapply(Data[,1],function(x){
                             parts<-strsplit(x,"\\|")[[1]]
                             y<-paste(gsub("(mature=)|(Gene=)","",parts[grepl("mature|Gene",parts)]),collapse="-")
                             return(y)
                          })
          

          示例

           Data<-data.frame(col1=c("mature=hsa-miR-5087|mir_Family=-|Gene=OR4F5","mature=hsa-miR-26a-1-3p|mir_Family=mir-26|Gene=OR4F9"),col2=1:2,stringsAsFactors=F)
          
          > Data[,1]
          [1] "mature=hsa-miR-5087|mir_Family=-|Gene=OR4F5"          "mature=hsa-miR-26a-1-3p|mir_Family=mir-26|Gene=OR4F9"
          
          > sapply(Data[,1],function(x){
          +                        parts<-strsplit(x,"\\|")[[1]]
          +                        y<-paste(gsub("(mature=)|(Gene=)","",parts[grepl("mature|Gene",parts)]),collapse="-")
          +                        return(y)
          +                     })
                   mature=hsa-miR-5087|mir_Family=-|Gene=OR4F5 mature=hsa-miR-26a-1-3p|mir_Family=mir-26|Gene=OR4F9 
                                          "hsa-miR-5087-OR4F5"                             "hsa-miR-26a-1-3p-OR4F9"
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-07-03
            • 1970-01-01
            • 1970-01-01
            • 2019-10-30
            • 1970-01-01
            • 2011-03-15
            • 2022-09-30
            • 2017-09-17
            相关资源
            最近更新 更多