好的我有一个使用data.frames构建的复杂功能,并且为了加快速度,我转向了data.table。我对此完全陌生,所以我很困惑。无论如何,我已经做了一个更简单的玩具示例,我想做什么,但我无法弄清楚如何将其转换为data.table格式。以下是data.frame形式的示例:
rows <- 10
data1 <- data.frame( id =1:rows,
a = seq(0.2, 0.55, length.out = rows),
b = seq(0.35, 0.7, length.out = rows),
c = seq(0.4, 0.83, length.out = rows),
d = seq(0.6, 0.87, length.out = rows),
e = seq(0.7, 0.99, length.out = rows),
f = seq(0.52, 0.90, length.out = rows)
)
DT1 <- data.table(data1) #for later
data2 <- data.frame( id =3:1,
a = rep(3, 3),
d = rep(2, 3),
f = rep(1, 3)
)
m.names <- c("a", "d", "f")
data1[match(data2$id, data1$id),m.names] <- data1[match(data2$id, data1$id),m.names] + data2[match(data2$id, data1$id),m.names]
所以请注意,在最后一步中,我希望在预先存在的数字和新数据之间执行添加,并将其矢量化为多个列。
在data.table格式中,我只是走了这么远:
DT1[id %in% data2$id, m.names, with=FALSE]
这会选择我要添加的值,但之后我就输了。我将不胜感激任何帮助!
编辑:
好的我已经找到了它的一部分 - 我可以使用上面的最后一行代码来实现矢量化的添加部分,使用data2来存储添加的值,如下所示:
data2[,m.names] <- data2[,m.names] + data.frame(DT1[id %in% data2$id, m.names, with=FALSE])
即使有250万行(在DT1中)和10,000行在data2和6个匹配列中,这只需要0.004秒,但我仍然需要将新数据2分配给数据1中相应的动态分配列
答案 0 :(得分:3)
这是另一种方式,使用devel version data.table v1.9.5
:
require(data.table) ## v1.9.5+
setDT(data1) ## data1 is now a data.table
cols1 = c("a", "d", "f")
cols2 = paste0("i.", cols1)
setkey(data1, id) ## setkey and prepare for join
data1[data2, (cols1) := mapply(`+`, mget(cols1), mget(cols2), SIMPLIFY=FALSE)]
# id a b c d e f
# 1: 1 3.2000000 0.3500000 0.4000000 2.60 0.7000000 1.5200000
# 2: 2 3.2388889 0.3888889 0.4477778 2.63 0.7322222 1.5622222
# 3: 3 3.2777778 0.4277778 0.4955556 2.66 0.7644444 1.6044444
# 4: 4 0.3166667 0.4666667 0.5433333 0.69 0.7966667 0.6466667
# 5: 5 0.3555556 0.5055556 0.5911111 0.72 0.8288889 0.6888889
# 6: 6 0.3944444 0.5444444 0.6388889 0.75 0.8611111 0.7311111
# 7: 7 0.4333333 0.5833333 0.6866667 0.78 0.8933333 0.7733333
# 8: 8 0.4722222 0.6222222 0.7344444 0.81 0.9255556 0.8155556
# 9: 9 0.5111111 0.6611111 0.7822222 0.84 0.9577778 0.8577778
# 10: 10 0.5500000 0.7000000 0.8300000 0.87 0.9900000 0.9000000
表单x[i]
的 join 是在密钥列id
上执行的。对于 data2 的id
列的每一行,都会找到 data1 中相应的匹配行。例如,对于来自 data2 的id = 2
,匹配的行是 data1 中的第二行。
在我们所有匹配的行之后,我们会在j
中评估表达式,该表达式通过添加{col1
中提供的 data1 列来更新{1}}和mget(cols1)
。
mget(cols2)
是使用cols2
前缀生成的,该前缀从 data.table i 中获取值 - 此处为 data2 。
HTH
答案 1 :(得分:1)
一种方法是在set
循环中使用for
,因为这涉及多个列。将第二个数据集转换为&#39; data.table&#39; (DT2),使用&#39; id&#39;设置密钥。列,并加入&#39; data1&#39;。为&#39; m.names&#39;创建列索引向量。加入后创建的数据集(&#39; indx1&#39;)和i.
列中的列(&#39; indx2&#39;)。使用for
循环,set
NA
元素在&#39; m.names&#39;列到&#39; 0&#39;,然后根据&lt; indx1&#39;汇总相应的列。和&#39; indx2&#39;。
DT2 <- as.data.table(data2)
DTNew <- setkey(DT2, id)[data1]
indx1 <- match(m.names, names(DTNew))
indx2 <- grep('i\\.', names(DTNew))
for(k in seq_along(indx1)){
set(DTNew, i=which(is.na(DTNew[[indx1[k]]])), j= indx1[k], value=0)
set(DTNew, i=NULL, j= indx2[k], value = DTNew[[indx1[k]]]+
DTNew[[indx2[k]]])
}
res <- DTNew[,2:4 := NULL]
setnames(res, names(data1))
使用修改过的&#39; data1&#39;
进行检查 data1[match(data2$id, data1$id),m.names] <- data1[match(data2$id,
data1$id),m.names] + data2[match(data2$id, data1$id),m.names]
all.equal(setDF(res), data1)
#[1] TRUE
On a 1e6 dataset,
set.seed(24)
data1 <- cbind(id=1:1e6,as.data.frame(matrix(rnorm(1e6*10), ncol=10,
dimnames=list(NULL, letters[1:10])) ))
set.seed(46)
data2 <- data.frame(id= sample(1:1000, 100, replace=FALSE),
a= rnorm(100), d=rnorm(100), f= rnorm(100))
m.names <- c("a", "d", "f")
DT2 <- as.data.table(data2)
system.time({
DTNew <- setkey(DT2, id)[data1]
indx1 <- match(m.names, names(DTNew))
indx2 <- grep('i\\.', names(DTNew))
for(k in seq_along(indx1)){
set(DTNew, i=which(is.na(DTNew[[indx1[k]]])), j= indx1[k], value=0)
set(DTNew, i=NULL, j= indx2[k], value = DTNew[[indx1[k]]]+
DTNew[[indx2[k]]])
}
res <- DTNew[,2:4 := NULL]
setnames(res, names(data1))
})
# user system elapsed
# 0.082 0.005 0.086
答案 2 :(得分:0)
好的,感谢@David Arenburg提出的建议。我已经稍微修改了它以获得以下我的首选解决方案
text <- NULL
for(i in 1:length(m.names)){
text <- paste0(text, m.names[i], " = ", m.names[i], " + i.", m.names[i], ", ")
}
expr <- parse(text = paste0("\":=\"(", substr(text, 1, nchar(text)-2), ")" ))
res2 <- DT1[data2, eval(expr)]