我想选择data.table(TARGET
)的特定行值(此处为DT1
),其中过滤器标准位于其他data.table(DT2
)中。
它不是一个精确的过滤器,因为如果DT2
中的值为3,则DT1
中的此值为最小值和最大值。我还有一个字符串,其中包含一个特定的模式。
例如:A = 3
中的DT2
和DT1
中的相应行包含minA = 3
中的maxA = 6
,C = "Mon"
和C = "Mon,Tue"
。
DT1
INDEX1 minA maxA C TARGET
9 : 9 3 6 Mon,Tue 109
DT2
A C INDEX2
1: 3 Mon 1
我正在寻找具有此值所在范围的行以及最大目标值。
我有以下简化示例:
# 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
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
仅用于扩展和测试。
到目前为止我的解决方案如下:
我编写了一个函数foo()
,它接受过滤器输入值并返回DT1的索引(或其他更有用的变量)。
foo <- function(i.A, i.C){
DT1[INDEX1 %in% grep(i.C,C) & minA <= i.A & maxA >= i.A,][TARGET == max(TARGET),]
}
我为DT2的每一行调用此函数
DT2[, foo(i.A = A, i.C = C), by = INDEX2]
与outout:
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中有更多行。功能需要更长时间,我想知道是否有更好/更快的方式进行这种过滤?
也许有可能&#34;升级&#34; foo()
以便它可以处理整个列而不是单行?
如果可能,我想避免像这样扩展我的DT1:
我认为,我有一个比这些问题更复杂的过滤器:
提前感谢您的帮助。
答案 0 :(得分:0)
新解决方案
我意识到通过更大的data.table的每一行花费了很多时间,所以我构建了一个新的函数foo_new
,它反过来工作:
foo_new <- function(data, i.A, i.C){
data[C %in% i.C & A %between% i.A, INDEX2]
}
我没有用一行DT1加工DT2的每一行,而是选择DT2中与DT1的一行值相匹配的每一行。
完成DT2的排序是因为我需要具有最高TARGET
值的行。此外,如果已经选择了DT2中的一行,则会在下一次迭代时将其删除。
整个过程加速了很多:
function user system elapsed
foo 61.511 0.327 62.052
foo_new 0.045 0.003 0.047
这只是个案,当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]]
}