2017-07-13 6 views
1

フィルタ基準が他のdata.tableにあるdata.table(DT1)の特定の行の値(ここではTARGET)を選択したいとします。 (DT2)。 これは正確なフィルタではありません。DT2に値3がある場合、この値の最小値と最大値はDT1です。また、私は特定のパターンを含む文字列を持っています。 たとえばA = 3DT2とし、対応する行をDT1とした場合、minA = 3,maxA = 6およびC = "Mon"が​​である。他のdata.tableのフィルタで指定されたdata.tableの行を選択

DT1 
    INDEX1 minA maxA  C TARGET 
9 :  9 3 6 Mon,Tue 109 

DT2 
    A C INDEX2 
1: 3 Mon  1 

私は、この値が存在する範囲と最大目標値を持つ行を探しています。

DT1 
    INDEX1 minA maxA  C TARGET 
1 :  1 1 4 Mon,Tue 101 
2 :  2 1 5 Mon,Wed 102 
3 :  3 1 6 Tue,Thu 103 
4 :  4 2 4 Wed,Thu 104 
5 :  5 2 5 Mon,Tue 105 
6 :  6 2 6 Mon,Wed 106 
7 :  7 3 4 Tue,Thu 107 
8 :  8 3 5 Wed,Thu 108 
9 :  9 3 6 Mon,Tue 109 
10:  10 4 4 Mon,Wed 110 
11:  11 4 5 Tue,Thu 111 
12:  12 4 6 Wed,Thu 112 

DT2 
    A C INDEX2 
1: 3 Mon  1 
2: 4 Thu  2 

私はちょうどスケーリングおよびテストのためsizeが含まれていました。このようになります

# version 1.9.6 
library(data.table) 

DT1 <- data.table(INDEX1 = 1:12, 
        minA = c(1,1,1,2,2,2,3,3,3,4,4,4), 
        maxA = c(4,5,6), 
        C = c("Mon,Tue", "Mon,Wed", "Tue,Thu", "Wed,Thu"), 
        TARGET = c(101:112)) 
size <- 2 
DT2 <- data.table(A = rep(c(3,4), size), 
        C = rep(c("Mon", "Thu"), size), 
        INDEX2 = 1:(2*size)) 

は、私は、次の簡単な例を持っています。

私のソリューションは、これまでに以下の通りです:

私は、フィルタの入力値を取り、DT1のインデックス(または他のいくつかのより多くの有用な変数)を返す関数foo()を書きました。

foo <- function(i.A, i.C){ 
    DT1[INDEX1 %in% grep(i.C,C) & minA <= i.A & maxA >= i.A,][TARGET == max(TARGET),] 
} 

私はoutoutとDT2

DT2[, foo(i.A = A, i.C = C), by = INDEX2] 

の行ごとに、この関数を呼び出す:これは、ため正常に動作

INDEX2 INDEX1 minA maxA  C TARGET 
1:  1  9 3 6 Mon,Tue 109 
2:  2  12 4 6 Wed,Thu 112 

そしてここでは私の問題です小さなdata.tablesが、私はDT2の多くの行を持っています。関数にははるかに時間がかかり、このようなフィルタリングのためのより良い/より速い方法があるのだろうかと思っていました。 foo()を「アップグレード」して、単一行ではなく列全体を処理できることはありますか?

私はここのように私DT1を展開して避けたい可能であれば:

と私は考えて、私はこれらの質問に比べて、より複雑なフィルタを持っている:

ご協力いただきありがとうございます。

答えて

0

新しいソリューション

私は大きなdata.tableの各ラインを通過すると、多くの時間を要することに気づいたので、私は他の方法で回避します新機能foo_new構築:

foo_new <- function(data, i.A, i.C){ 
    data[C %in% i.C & A %between% i.A, INDEX2] 
} 

DT2のすべての行をDT1の行で機械加工するのではなく、DT1の1行の値と一致するDT2のすべての行を選択します。 DT2の注文は、最高のTARGET値の行が必要なために行われます。また、DT2の行がすでに選択されている場合は、次の反復のために削除されます。

全体のプロセスは、多くの高速化される:

function user system elapsed 
    foo  61.511 0.327 62.052 
    foo_new 0.045 0.003 0.047 

これでprobaly場合のみ、DT1がDT2よりも小さいときに - 私の場合です。


ここに私の全体のシミュレーションコード:

rm(list = ls()) 
library(data.table) 

DT1 <- data.table(INDEX1 = 1:12, 
        minA = c(1,1,1,2,2,2,3,3,3,4,4,4), 
        maxA = c(4,5,6), 
        C = c("Mon,Tue", "Mon,Wed", "Tue,Thu", "Wed,Thu"), 
        TARGET = c(101:112)) 

size <- 20000 
DT2 <- data.table(A = rep(c(3,4), size), 
        C = rep(c("Mon", "Thu"), size), 
        INDEX2 = 1:(2*size)) 

foo <- function(i.A, i.C){ 
    DT1[INDEX1 %in% grep(i.C, C) & 
     minA <= i.A & 
     maxA >= i.A, 
     ][TARGET == max(TARGET),] 
} 

foo_new <- function(data, i.A, i.C){ 
    data[C %in% i.C & A %between% i.A, INDEX2] 
} 

# with foo 
DT2[, foo(i.A = A, i.C = C), by = INDEX2]) 

# with foo_new 
DT1.ordered <- copy(DT1[order(TARGET, decreasing = TRUE)]) 
tmp.index <- list() 
DT2[, TARGET := as.numeric(NA)] 
for (i in c(1:dim(DT1.ordered)[1])) { 
    # i <- 1 
    restdata <- copy(DT2[is.na(TARGET),]) 
    tmp.index <- foo_new(data = restdata, 
         i.A = unlist(DT1.ordered[i, list(minA, maxA)]), 
         i.C = DT1.ordered[i, strsplit(C, ",")[[1]]]) 
    DT2[INDEX2 %in% tmp.index, TARGET := DT1.ordered[i, TARGET]] 
} 
関連する問題