我有两个data.table
,如下所示:
N = 10
A.DT <- data.table(a1 = c(rnorm(N,0,1)), a2 = NA))
B.DT <- data.table(b1 = c(rnorm(N,0,1)), b2 = 1:N)
setkey(A.DT,a1)
setkey(B.DT,b1)
我尝试通过更改for循环将我之前的data.frame
实现更改为data.table
实现,如下所示:
for (i in 1:nrow(B.DT)) {
for (j in nrow(A.DT):1) {
if (B.DT[i,b2] <= N/2
&& B.DT[i,b1] < A.DT[j,a1]) {
A.DT[j,]$a2 <- B.DT[i,]$b1
break
}
}
}
我收到以下错误消息:
Error in `[<-.data.table`(`*tmp*`, j, a2, value = -0.391987468746123) :
object "a2" not found
我认为我访问data.table
的方式并不完全正确。我是新手。我想有一种更快捷的方法,就是在两个数据表中上下循环。
我想知道上面显示的循环是否可以简化/矢量化。
编辑复制/粘贴的data.table数据:
# A.DT
a1 a2
1 -1.4917779 NA
2 -1.0731161 NA
3 -0.7533091 NA
4 -0.3673273 NA
5 -0.159569 NA
6 -0.1551948 NA
7 -0.0430574 NA
8 0.1783496 NA
9 0.4276034 NA
10 1.0697412 NA
# B.DT
b1 b2
1 0.64229018 1
2 1.00527902 2
3 0.24746294 3
4 -0.50288835 4
5 0.34447791 5
6 -0.22205129 6
7 0.60099079 7
8 -0.70242284 8
9 0.6298599 9
10 0.08917988 10
我期望的输出:
# OUTPUT
a1 a2
1 -1.4917779 NA
2 -1.0731161 NA
3 -0.7533091 NA
4 -0.3673273 NA
5 -0.159569 NA
6 -0.1551948 NA
7 -0.0430574 NA
8 0.1783496 -0.50288835
9 0.4276034 0.24746294
10 1.0697412 0.64229018
算法向下移动一个表,并且对于每一行向上移动另一个表,检查一些条件并相应地修改值。更具体地说,它下降B.DT,并且B.DT中的每一行上升A.DT并且将a1分配给b1的第一个值,使得b1小于a1。在分配之前检查附加条件(在该示例中b2等于或小于5)。
0.64229018是B.DT中的第一个值,它被分配到A.DT的最后一个单位。 1.00527902是B.DT中的第二个值,但它未被分配,因为它大于A.DT中的所有其他值。 0.24746294是B.DT中的第三个值,它被分配给A.DT中的第二个最后一个单位。 -0.50288835是B.DT中的第四个值,它被分配给A.DT中的单元#8 0.34447791是B.DT中的第五个值,由于它太大而未被分配。
这当然是一个简化的问题(因此可能没有多大意义)。感谢您的时间和意见。
答案 0 :(得分:1)
您的代码将会更改:
A.DT[j,]$a2 <- B.DT[i,]$b1
到
A.DT$a2[j,] <- B.DT[i,]$b1
至于更有效地使用data.table
,我会把它留给那些比我更专业的人......
答案 1 :(得分:1)
创建data.table后,几乎不需要常规分配运算符<-
,而是要使用:=
,而 j
位置的括号。
(避免<-
的原因是<-
创建了对象的副本,而:=
则没有,因此效率很高)
因此,对您的代码进行首次修改将是:
# FROM: A.DT[j,]$a2 <- B.DT[i,]$b1
# TO:
A.DT[j, a2 := B.DT[i, b1] ]
现在,data.table
(许多)最佳功能之一就是它的by
参数,这有助于消除大量for
循环和*ply
调用。
在这种特定情况下,您可以按如下方式清理双循环:
set.seed(201)
A.DT <- data.table(a1 = rnorm(N,0,1), key="a1") # no need to create a2 if it will be NA. If you do, make sure it is as.numeric(NA)
B.DT <- data.table(b1 = rnorm(N,0,1), b2 = 1:N, key="b2")
# Assign to a2 in A.DT
A.DT[
, a2 := B.DT[ b2 <= N/2 & b1 < a1] [1, b1]
, by=a1
]
> A.DT
a1 a2
1: -2.30403431 NA
2: -1.69658097 NA
3: -1.28548252 NA
4: -0.34454603 -0.6478531
5: -0.07503189 -0.6478531
6: 0.05593404 -0.6478531
7: 0.18900414 -0.6478531
8: 0.26693735 0.2238094
9: 0.28606069 0.2238094
10: 0.32576373 0.2238094
key
s。B.DT
的键更改为`b2。