12

R での特定のコーディングの問題に対する効率の提案をお願いしたいと思います。次のスタイルの文字列ベクトルがあります。

[1] "HGVSc=ENST00000495576.1:n.820-1G>A;INTRON=1/1;CANONICAL=YES"
[2] "DISTANCE=2179"                                              
[3] "HGVSc=ENST00000466430.1:n.911C>T;EXON=4/4;CANONICAL=YES"    
[4] "DISTANCE=27;CANONICAL=YES;common"

ベクトルの各要素では、単一のエントリは で区切られており、ほとんど;の単一のエントリの形式は ですKEY=VALUE。ただし、フォーマットしか持たないエントリもいくつかありますKEY([4] の「共通」を参照)。この例では、15 の異なるキーがあり、すべてのキーがベクトルの各要素に表示されるわけではありません。15 の異なるキーは次のとおりです。

names <- c('ENSP','HGVS','DOMAINS','EXON','INTRON', 'HGVSp', 'HGVSc','CANONICAL','GMAF','DISTANCE', 'HGNC', 'CCDS', 'SIFT', 'PolyPhen', 'common')

このベクトルから、次のようなデータフレームを作成したいと思います。

ENSP HGVS DOMAINS EXON INTRON HGVSp                        HGVSc CANONICAL
1    -    -       -    -    1/1     - ENST00000495576.1:n.820-1G>A       YES
2    -    -       -    -      -     -                            -         -
3    -    -       -  4/4      -     -   ENST00000466430.1:n.911C>T       YES
4    -    -       -    -      -     -                            -       YES
GMAF DISTANCE HGNC CCDS SIFT PolyPhen common
1    -        -    -    -    -        -      -
2    -     2179    -    -    -        -      -
3    -        -    -    -    -        -      -
4    -       27    -    -    -        -    YES

問題を解決するためにこの関数を書きました:

unlist.info <- function(names, column){
  info.mat <- matrix(rep('-', length(column)*length(names)), nrow=length(column), ncol=length(names), dimnames=list(c(), names))
  info.mat <- as.data.frame(info.mat, stringsAsFactors=F)

  for (i in 1:length(column)){
    info <- unlist(strsplit(column[i], "\\;"))
    for (e in info){
      e <- unlist(strsplit(e, "\\="))
      j <- which(names == e[1])
      if (length(e) > 1){
        # KEY=VALUE. The value might contain a = as well
        value <- paste(e[2:length(e)], collapse='=')
        info.mat[i,j] <- value
      }else{
        # only KEY
        info.mat[i,j] <- 'YES'
      }
    }
  }
  return(info.mat)
}

そして、私は電話します:

mat <- unlist.info(names, vector)

これは機能しますが、本当に遅いです。また、100.000 を超えるエントリを持つベクトルを処理しています。今では、R ではループが洗練されておらず非効率的であることに気付き、関数をデータ フレームに適用するという概念に精通しています。ただし、ベクトルのすべてのエントリには、KEY=VALUEまたはKEYエントリの異なるサブセットが含まれているため、より効率的な関数を思いつくことができませんでした。

4

2 に答える 2

11

どうぞ:

データを再作成します。

x <- c(
  "HGVSc=ENST00000495576.1:n.820-1G>A;INTRON=1//1;CANONICAL=YES",
  "DISTANCE=2179",
  "HGVSc=ENST00000466430.1:n.911C>T;EXON=4//4;CANONICAL=YES",
  "DISTANCE=27;CANONICAL=YES;common"
)

希望する名前で名前付きベクターを作成します。これは、後で高速検索に使用されます。

names <- setNames(1:15, c('ENSP','HGVS','DOMAINS','EXON','INTRON', 'HGVSp', 'HGVSc','CANONICAL','GMAF','DISTANCE', 'HGNC', 'CCDS', 'SIFT', 'PolyPhen', 'common'))

各変数を行列内の正しい位置に割り当てるヘルパー関数を作成します。次に、およびを使用lapplystrsplitます。

assign <- function(x, names){
  xx <- sapply(x, function(i)if(length(i)==2L) i else c(i, "YES"))
  z <- rep(NA, length(names))
  z[names[xx[1, ]]] <- xx[2, ]
  z
}

sx <- lapply(strsplit(x, ";"), strsplit, "=")
ret <- t(sapply(sx, assign, names))
colnames(ret) <- names(names)
ret

結果:

     ENSP HGVS DOMAINS EXON   INTRON HGVSp HGVSc                          CANONICAL GMAF DISTANCE HGNC
[1,] NA   NA   NA      NA     "1//1" NA    "ENST00000495576.1:n.820-1G>A" "YES"     NA   NA       NA  
[2,] NA   NA   NA      NA     NA     NA    NA                             NA        NA   "2179"   NA  
[3,] NA   NA   NA      "4//4" NA     NA    "ENST00000466430.1:n.911C>T"   "YES"     NA   NA       NA  
[4,] NA   NA   NA      NA     NA     NA    NA                             "YES"     NA   "27"     NA  
     CCDS SIFT PolyPhen common
[1,] NA   NA   NA       NA    
[2,] NA   NA   NA       NA    
[3,] NA   NA   NA       NA    
[4,] NA   NA   NA       "YES" 
于 2012-10-16T11:38:42.547 に答える
3

これは、元のペアリングを利用した別のより高速なソリューションです...

##                   test elapsed replications relative average
## 2    thell_solution(x)    0.37         1000    1.000 0.00037
## 3   andrie_solution(x)    1.04         1000    2.811 0.00104
## 1 original_solution(x)    2.61         1000    7.054 0.00261

ペアリング[1] は常に最後のブール値を除いてペアリング[2] に割り当てられるため (... 元の文字列ベクトルでその 1 つのフラグが異なる方法で扱われる理由を理解していない...)、シーケンスとベクトルの事実を利用できます。値なしで名前が指定された場合 (つまり、 x[5] == NA ) に NA が割り当てられ、名前を複数回呼び出す必要もありません。また、strsplit は正規表現を使用するため、交互に実行できます。

# Let `x` be as @Andrie made it in his answer.  Let `names` be as you had
# in the original question.

# A pre-built dummy record and empty list.
na.record <- setNames(rep(NA, time = length(names)), names)
y <- list()

do.call(rbind, lapply(strsplit(x, "(;|=)"), FUN = function(x) {
    x_seq <- seq.int(to = length(x), by = 2)
    y[x[x_seq]] <- x[x_seq + 1]
    y[is.na(y)] <- "YES"
    na.record[x[x_seq]] <- y
    na.record
}))


##      ENSP HGVS DOMAINS EXON   INTRON HGVSp HGVSc                         
## [1,] NA   NA   NA      NA     "1//1" NA    "ENST00000495576.1:n.820-1G>A"
## [2,] NA   NA   NA      NA     NA     NA    NA                            
## [3,] NA   NA   NA      "4//4" NA     NA    "ENST00000466430.1:n.911C>T"  
## [4,] NA   NA   NA      NA     NA     NA    NA                            
##      CANONICAL GMAF DISTANCE HGNC CCDS SIFT PolyPhen common
## [1,] "YES"     NA   NA       NA   NA   NA   NA       NA    
## [2,] NA        NA   "2179"   NA   NA   NA   NA       NA    
## [3,] "YES"     NA   NA       NA   NA   NA   NA       NA    
## [4,] "YES"     NA   "27"     NA   NA   NA   NA       "YES"
于 2012-10-16T21:07:50.790 に答える