一些示例数据:
library(data.table)
mydat <- data.table(id1=rep(c("A","B","C"),each=3),
id2=c("D","E","G", "D","E","F","G","E","D"),
val=c(1,2,4,1,2,3, 4,2,1))
哪个给
id1 id2 val
1: A D 1
2: A E 2
3: A G 4
4: B D 1
5: B E 2
6: B F 3
7: C G 4
8: C E 2
9: C D 1
我的目标是获取id2,val的唯一值,然后生成一个依赖于唯一值的变量(例如,如下所示的唯一观察值之和)。然后,应将此变量放入原始data.table
的一列中。我经常发现自己在编写如下代码:
## This is the most obvious way
tmp <- unique(mydat[,.(id2,val)])
tmp[,weight:=val/sum(val)]
tmp[,val:=NULL]
mydat <- merge(mydat,tmp,by="id2",all.x=TRUE)
## A second option which doesn't require merging
mydat[,first:=FALSE]
mydat[mydat[,.I[1],by=.(id2)]$V1,first:=TRUE]
mydat[first==TRUE,weight2:=val/sum(val)]
mydat[,weight2:=max(weight,na.rm = TRUE),by=.(id2)]
mydat[,first:=NULL]
这给
id2 id1 val weight weight2
1: D A 1 0.1 0.1
2: D B 1 0.1 0.1
3: D C 1 0.1 0.1
4: E A 2 0.2 0.2
5: E B 2 0.2 0.2
6: E C 2 0.2 0.2
7: F B 3 0.3 0.3
8: G A 4 0.4 0.4
9: G C 4 0.4 0.4
完全出于好奇,是否有一种更清洁的方法(更多data.table)来做到这一点?也许有自我加入?性能非常重要,因为我正在使用的实际数据往往很大。
答案 0 :(得分:4)
我同意@thelatemail的观点,OP中的方法已经非常干净了。
性能非常重要,因为我正在使用的实际数据往往很大。
如果必须使用此结构,则有:
setorder(mydat, id2)
mydat[unique(id2), on=.(id2), mult="first", w2 := val/sum(val)]
mydat[, w2 := nafill(w2, type="locf")]
我正在排序,因为这已显示在所需的输出中。要保持原始排序,请放下setorder
并将最后一行更改为mydat[order(id2), w2 := nafill(w2, type="locf")]
。
nafill
功能在1.12.3+中可用(因此在CRAN上尚不可用)。
我建议改为使用一组规范化/“整洁”的表:val
是id2
的属性,因此您可以有一个包含此类内容的id2
表。
# same as OP's tmp
id2DT = unique(mydat[, .(id2, val)])
setkey(id2DT, id2)
id2DT[, w := val/sum(val)]
# drop redundant repeating val unless you really need it there
# to save on space and improve readability
mydat[, val := NULL]
# merge w in if/when needed
mydat[, w := id2DT[.SD, on=.(id2), x.w]]
答案 1 :(得分:2)
这是免合并选项:
total_val <- mydat[!duplicated(id2, val), sum(val)] # Just the scalar we are after
mydat[, `:=`(val = val[1], weight = val[1] / total_val), by = id2]
# id1 id2 val weight
# 1: A D 1 0.1
# 2: B D 1 0.1
# 3: C D 1 0.1
# 4: A E 2 0.2
# 5: B E 2 0.2
# 6: C E 2 0.2
# 7: B F 3 0.3
# 8: A G 4 0.4
# 9: C G 4 0.4