R 如何执行一个;“串行连接”;在data.table中?
我有两个数据表:一个实验数据表R 如何执行一个;“串行连接”;在data.table中?,r,data.table,R,Data.table,我有两个数据表:一个实验数据表x和一个类别查找表dict library(data.table) set.seed(123) x = data.table(samp=c(1,1,2,3,3,3,4,5,5,5,6,7,7,7,8,9,9,10,10), y=rnorm(19)) x samp y #1: 1 -0.56047565 #2: 1 -0.23017749 #3: 2 1.55870831 #4: 3 0.07050839 #5: 3 0.
x
和一个类别查找表dict
library(data.table)
set.seed(123)
x = data.table(samp=c(1,1,2,3,3,3,4,5,5,5,6,7,7,7,8,9,9,10,10), y=rnorm(19))
x
samp y
#1: 1 -0.56047565
#2: 1 -0.23017749
#3: 2 1.55870831
#4: 3 0.07050839
#5: 3 0.12928774
#6: 3 1.71506499
#7: 4 0.46091621
#8: 5 -1.26506123
#9: 5 -0.68685285
#10: 5 -0.44566197
#11: 6 1.22408180
#12: 7 0.35981383
#13: 7 0.40077145
#14: 7 0.11068272
#15: 8 -0.55584113
#16: 9 1.78691314
#17: 9 0.49785048
#18: 10 -1.96661716
#19: 10 0.70135590
dict = data.table(samp=c(1:5, 4:8, 7:10), cat=c(rep(1,length(1:5)), rep(2,length(4:8)), rep(3,length(7:10))))
dict
# samp cat
# 1: 1 1
# 2: 2 1
# 3: 3 1
# 4: 4 1
# 5: 5 1
# 6: 4 2
# 7: 5 2
# 8: 6 2
# 9: 7 2
# 10: 8 2
# 11: 7 3
# 12: 8 3
# 13: 9 3
# 14: 10 3
对于每个samp
,我需要首先计算与之关联的所有y
的乘积。然后,我需要根据dict$cat
中指定的每个样本类别计算这些产品的总和。请注意,每个samp
映射到多个dict$cat
一种方法是立即合并x
和dict
,允许行复制(allow.cartesian=T
):
然而,我不知道是否可以避免这一加入步骤。这有几个原因-例如,如果x
很大,复制将使用额外的内存(对吗?)。此外,这些具有重复行的汇总表非常混乱,使得分析更容易出错
因此,我考虑在每个dict$cat
中使用示例在x
中进行二进制搜索。我知道如何对单个类别执行此操作,因此对所有类别执行此操作的丑陋方式是使用循环:
setkey(x, samp)
setkey(dict,samp)
pool = vector("list")
for(n in unique(dict$cat)){
thisCat = x[J(dict[cat==n])]
setkey(thisCat, samp)
step1 = thisCat[, list(prodY=prod(y)[1], cat=cat[1]), by="samp"]
pool[[n]] = step1[, sum(prodY), by="cat"]
}
resMet2 = rbindlist(pool)
当然,这种循环是要避免的。因此,我想知道是否有任何方法可以以某种方式获取
数据.table
来迭代J()
中的键值?您不妨先将x
折叠到samp
级别
xprod = x[, .(py = prod(y)), by=samp]
合并
res2 <- xprod[dict, on = "samp"][, sum(py), by=cat]
identical(res2, resMet2) # test passed
重新标记样本ID非常简单,因此这是真实的。IIUC,我将您的问题表述如下:对于每个
dict$cat
,我希望得到对应于该cat
的每个样本的prod(y)
,然后将它们全部加起来
现在让我们一步一步地构造这个:
对于每个dict$cat
-听起来您需要按cat
分组:
dict[, ,by=cat]
剩下的就是正确地加注j
对于该组的每个样本,您需要从x
获取prod(y)
:
从与该组的samp
对应的x
中提取那些行(使用.SD
,它代表数据子集),并计算它们上的prod(y)
,按samp
分组。太好了
我们仍然需要对它们进行汇总
sum(x[samp %in% .SD$samp, prod(y), by=samp]$V1)
我们得到了完整的j
表达式。让我们将其全部插入:
dict[, sum(x[samp %in% .SD$samp, prod(y), by=samp]$V1), by=cat]
# cat V1
# 1: 1 1.7770272
# 2: 2 0.7578771
# 3: 3 -1.0295633
希望这有帮助
注1:这里有一些多余的prod(y)
计算,但好处是我们没有实现太多中间数据。所以它的内存效率很高。如果您有太多的组,这可能会变慢。。您可能需要在另一个变量中计算prod(y)
,如下所示:
x_p = x[, .(p = prod(y)), by=samp]
这样,我们可以简化j
,如下所示:
dict[, x_p[samp %in% .SD$samp, sum(p)], by=cat]
注意2:在%
表达式中的%在x的
列上第一次运行时创建一个自动索引,从那时起使用基于二进制搜索的子集。因此,不必担心矢量扫描带来的性能问题。我不知道%in%是以这种方式优化的。请参阅。在某个时候,我会把它包装成一个小插曲…foverlaps()
在这里可能会有点过头。就像更简单的解决方案。
dict[, sum(x[samp %in% .SD$samp, prod(y), by=samp]$V1), by=cat]
# cat V1
# 1: 1 1.7770272
# 2: 2 0.7578771
# 3: 3 -1.0295633
x_p = x[, .(p = prod(y)), by=samp]
dict[, x_p[samp %in% .SD$samp, sum(p)], by=cat]