2017-11-08 5 views
1

言ってやるが、私は以下のようなデータフレームがあります。R:高速クエリ/マッチデータフレーム

library(dplyr) 
library(microbenchmark) 
library(ggplot2) 

dfr <- data.frame(name=c("bill","john","alice","sara"), 
job=c("accounting","business","finance","business"), 
stringsAsFactors=F) 

    name  job 
1 bill accounting 
2 john business 
3 alice finance 
4 sara business 

をそして私は名前のクエリ(文字ベクトル)を持っています。私は、データフレームの位置「名前」に、クエリの各要素を検索し、いくつかの条件を指定した行全体を取得したいと思います

qe <- c("john","bill","mark","bill") 

:クエリで

  • 重複はの
  • 注文を保存しなければなりませんクエリは

(NAの追加で)

  • 比類のないクエリを保存しなければならない保存されなければなりません私の試みは以下の機能でした:

    loopy <- function(qe=NULL,dfr=NULL) 
    { 
        elist <- vector("list",length=length(qe)) 
        for(i in 1:length(qe)) 
        { 
        g <- grep(qe[i],dfr$name) 
        if(length(g)==0) { 
         elist[[i]] <- data.frame(name=qe[i],job=NA,stringsAsFactors=F) 
        }else{ 
         elist[[i]] <- dfr[g,] 
        } 
        } 
        return(bind_rows(elist)) 
    } 
    
    loopy(qe,dfr) 
    
        name  job 
    1 john business 
    2 bill accounting 
    3 mark  <NA> 
    4 bill accounting 
    

    私の実際のデータは数千の行で遅すぎます。私はdplyrのアプローチを試みると思った。

    dp_lj <- function(qe=NULL,dfr=NULL) 
    { 
        edf <- data.frame(name=qe,stringsAsFactors=F) 
        edf <- left_join(edf,dfr,by="name") 
        return(edf) 
    } 
    dp_lj(qe,dfr) 
    
        name  job 
    1 john business 
    2 bill accounting 
    3 mark  <NA> 
    4 bill accounting 
    

    left_join私が望む結果を与えるように思われます。しかし、驚くべきことに、これは私の虚偽の機能よりも遅かった。しばらく回って、私はマッチアプローチを思いついた。

    matchy <- function(qe=NULL,dfr=NULL) 
    { 
        edf <- dfr[match(qe,dfr$name),] 
        pos <- match(NA,edf$name) 
        if(!is.na(pos)) edf[pos,]$name <- qe[pos] 
        rownames(edf) <- 1:nrow(edf) 
        return(edf) 
    } 
    matchy(qe,dfr) 
    
        name  job 
    1 john business 
    2 bill accounting 
    3 mark  <NA> 
    4 bill accounting 
    

    これはこれまでのところ最も速いです。 %in%を使った試みは実際には機能しませんでした ​​3210

    autoplot(microbenchmark(loopy(qe,dfr),dp_lj(qe,dfr),matchy(qe,dfr),times=500)) 
    
    Unit: microseconds 
          expr  min  lq  mean median  uq  max neval cld 
        loopy(qe, dfr) 426.274 461.0390 528.1194 481.7795 518.915 2659.955 500 b 
        dp_lj(qe, dfr) 919.311 982.9155 1146.0196 1030.1260 1129.088 4589.438 500 c 
    matchy(qe, dfr) 128.396 154.4710 185.1209 169.0875 186.471 736.397 500 a 
    

    autoplot

    あまりにも多くの努力を取らないより速く解決策がある場合、私は好奇心旺盛です。また、実際の大規模なデータセットで実行すると、ここで見られるパフォーマンスが同等かどうかはテストしていません。

    EDIT --------------------------------------------- ----------------------------

    提案されているようにdata.tableアプローチを追加しました。

    dt <- function(qe=NULL,dfr=NULL) 
    { 
        setDT(dfr) 
        qe <- data.table(name=qe) 
        merge(qe, dfr, "name", all.x = TRUE, sort = FALSE) 
    } 
    

    は、長さ18と100,000行のデータフレームのクエリを使用して試験しました。現実のパフォーマンスをよりよく比較することができます。

    mb <- microbenchmark(loopy(qe,dfr),dp_lj(qe,dfr),matchy(qe,dfr),dt(qe,dfr),times=200) 
    autoplot(mb) 
    

    plot2

  • +1

    あなたは 'fastmatch'パッケージをチェックアウトするかもしれません。これは複数の検索で 'match 'を破棄する' match'のためのドロップイン関数を持っています。 – lmo

    +0

    その小さなサンプルデータでベンチマークを実行しましたか?もしそうなら、結果は信頼できない。 –

    +0

    私もそう思った。大きなデータセットを試してみましょう。 – rmf

    答えて

    1

    1)あなたはdata.tableたびに

    withDT <- function(qe=NULL,dfr=NULL) { 
        dfr2 <- as.data.table(dfr) 
        setkey(dfr2, name) 
        return(dfr2[qe]) 
    } 
    
    N <- 200000 
    set.seed(123) 
    dfr <- data.frame(name= sample(1:30, N, replace = T), 
            job=sample(c("accounting","business","finance","business"), N, replace = T), 
            stringsAsFactors=F) 
    head(dfr) 
    qe <- 1:41 
    
    r <- microbenchmark(loopy(qe,dfr),dp_lj(qe,dfr), 
            matchy(qe,dfr), 
            withDT(qe, dfr),times=10) 
    autoplot(r) 
    r 
    Unit: milliseconds 
          expr   min   lq  mean  median   uq   max neval cld 
        loopy(qe, dfr) 2683.964539 2704.321688 2765.214321 2717.469448 2802.026508 3038.711852 10 b 
        dp_lj(qe, dfr) 10.799809 11.251819 12.675861 12.028161 12.849094 18.555524 10 a 
    matchy(qe, dfr) 1.741636 1.863862 2.892739 2.336564 2.616785 9.003637 10 a 
    withDT(qe, dfr) 3.348534 4.007463 5.836388 5.936607 6.656327 10.751368 10 a 
    

    をデータを変換ができますが、data.table一度、一度キーを設定して作成した場合、それは

    速い場合
    dt <- as.data.table(dfr) 
    setkey(dt, name) 
    
    withDT2 <- function(qe=NULL,dfr=NULL) { 
        return(dfr[qe]) 
    } 
    
    all.equal(withDT(qe, dfr), withDT2(qe, dt)) 
    
    r <- microbenchmark(loopy(qe,dfr),dp_lj(qe,dfr), 
            matchy(qe,dfr), 
            withDT(qe, dfr), 
            withDT2(qe, dt),times=10) 
    autoplot(r) 
    r 
          expr   min   lq   mean  median   uq   max neval cld 
        loopy(qe, dfr) 2721379.707 2753441.327 2822803.2351 2795276.9895 2862874.678 3060082.414 10 b 
        dp_lj(qe, dfr) 9181.361 9769.071 11084.7774 10708.5405 11709.925 16254.730 10 a 
    matchy(qe, dfr) 1783.983 1785.265 2798.4553 2183.7020 2659.131 8235.637 10 a 
    withDT(qe, dfr) 3280.845 3725.156 5076.5360 4097.7685 4714.831 13630.247 10 a 
    withDT2(qe, dt)  244.131  272.683  792.7672  520.9835  612.733 3895.182 10 a 
    
    関連する問題