R:在j子句中引用cut函数中的data.table字段

时间:2017-07-27 17:57:32

标签: r data.table

基本上,我有以下2 data.table s:

dt - 包含值字段(y)和分组字段(x
bk - 包含4个“ break ”字段(bn),用于描述{{1}中找到的每个组x的区间[1,inf]的存储区结构}}。每个dt代表桶的最小值(包括)并延伸到下一个桶(例如:bn = 1的4个桶是[1,3],[3,5],[ 5,10),[10,inf))。 注意,桶结构不一定是唯一的。

x

我的目标是向> #4 groups (x), each with a bucket structure defined breaks (bn). > bk<- data.table(x=c(1:4), b1=c(1,1,1,1), b2=c(3,3,4,4), b3=c(5,5,7,8), b4=c(10,10,10,10), key="x") > bk x b1 b2 b3 b4 1: 1 1 3 5 10 2: 2 1 3 5 10 3: 3 1 4 7 10 4: 4 1 4 8 10 > dt<- data.table(x=rep(c(1:4),5), y=rep(c(1:10),2), key="x") > dt x y 1: 1 1 2: 1 5 3: 1 9 4: 1 3 5: 1 7 6: 2 2 7: 2 6 8: 2 10 9: 2 4 10: 2 8 11: 3 3 12: 3 7 13: 3 1 14: 3 5 15: 3 9 16: 4 4 17: 4 8 18: 4 2 19: 4 6 20: 4 10 添加一个字段b,根据与{{0}对应的存储桶结构,指示记录所属的存储桶(1,2,3或4) 1}}。请参阅下面的所需输出:

dt

我最初的想法是加入两个x并使用 x y b 1: 1 1 1 #Buckets for x=1 2: 1 5 3 3: 1 9 3 4: 1 3 2 5: 1 7 3 6: 2 2 1 #Buckets for x=2 (same as 1) 7: 2 6 3 8: 2 10 4 9: 2 4 2 10: 2 8 3 11: 3 3 1 #Buckets for x=3 12: 3 7 3 13: 3 1 1 14: 3 5 2 15: 3 9 3 16: 4 4 2 #Buckets for x=4 17: 4 8 3 18: 4 2 1 19: 4 6 2 20: 4 10 4 函数返回每个记录的存储桶编号,但是我遇到了data.table参数的问题。首次尝试如下所示:

cut

如果我创建一个变量break来保存存储桶结构(例如,对于> bkt[dt, .(x, y, b=cut(y, breaks=c(b1, b2, b3, b4, "inf"), include.lowest=TRUE, labels=c(1:4)))] Error in cut.default(y, breaks = c(b1, b2, b3, b4, "inf"), include.lowest = TRUE, : 'breaks' are not unique = 1),则以下工作正如我预期的那样:

a

这仍然不是我的应用程序的实用解决方案,但我希望有人可以帮助我了解如何正确地将桶结构信息传递到x参数以获得类似的结果。我尝试了> a<- c(1, 3, 5, 10, "inf") > bkt[dt, .(x, y, b=cut(y, breaks=a, include.lowest=TRUE, labels=c(1:4)))] x y b 1: 1 1 1 2: 1 5 2 3: 1 9 3 4: 1 3 1 5: 1 7 3 6: 2 2 1 7: 2 6 3 8: 2 10 3 9: 2 4 2 10: 2 8 3 11: 3 3 1 12: 3 7 3 13: 3 1 1 14: 3 5 2 15: 3 9 3 16: 4 4 2 17: 4 8 3 18: 4 2 1 19: 4 6 3 20: 4 10 3 breaksclist函数的各种组合来传递正确的unlist参数,但没有运气。任何帮助/见解将不胜感激。谢谢!

完全披露,我是R的新手,这是我要发帖的第一篇文章。

3 个答案:

答案 0 :(得分:4)

稍微更改连接语法:

dt[bk, v := 
  cut(y, breaks = c(b1, b2, b3, b4, Inf), include.lowest = TRUE, labels = 1:4)
, by=.EACHI]

    x  y v
 1: 1  1 1
 2: 1  5 2
 3: 1  9 3
 4: 1  3 1
 5: 1  7 3
 6: 2  2 1
 7: 2  6 3
 8: 2 10 3
 9: 2  4 2
10: 2  8 3
11: 3  3 1
12: 3  7 2
13: 3  1 1
14: 3  5 2
15: 3  9 3
16: 4  4 1
17: 4  8 2
18: 4  2 1
19: 4  6 2
20: 4 10 3

这些结果与OP中的期望输出不同,但我认为错误在于cut参数的解释(我觉得令人困惑)。

这种方法非常不优雅,因为必须编写每个b1,...,b4;并且随着添加更多断点,它将无法很好地扩展。我同意@ NathanWerth关于重塑bk表的建议。他的方法也给出了OP期望的结果,而没有摆弄cut个参数。

旁注:正确的符号是Inf而不是"inf"

答案 1 :(得分:3)

您可以使用melt.data.tablebk数据集重组为更简单的形式:

bk_long <- melt.data.table(
  bk,
  id.vars = 'x',
  measure.vars = paste0('b', 1:4),
  value.name = 'y'
)
setkey(bk_long, x)
bk_long[, variable := NULL]
bk_long[, b := seq_len(.N), by = x]
bk_long
#     x  y b
#  1: 1  1 1
#  2: 1  3 2
#  3: 1  5 3
#  4: 1 10 4
#  5: 2  1 1
#  6: 2  3 2
#  7: 2  5 3
#  8: 2 10 4
#  9: 3  1 1
# 10: 3  4 2
# 11: 3  7 3
# 12: 3 10 4
# 13: 4  1 1
# 14: 4  4 2
# 15: 4  8 3
# 16: 4 10 4

然后像Frank建议的那样进行滚动加入:

bk_long[dt, on = c('x', 'y'), roll = TRUE]
#     x  y b
#  1: 1  1 1
#  2: 1  5 3
#  3: 1  9 3
#  4: 1  3 2
#  5: 1  7 3
#  6: 2  2 1
#  7: 2  6 3
#  8: 2 10 4
#  9: 2  4 2
# 10: 2  8 3
# 11: 3  3 1
# 12: 3  7 3
# 13: 3  1 1
# 14: 3  5 2
# 15: 3  9 3
# 16: 4  4 2
# 17: 4  8 3
# 18: 4  2 1
# 19: 4  6 2
# 20: 4 10 4

答案 2 :(得分:1)

经过多次尝试,我终于让findInterval工作了。

该方法类似于frank's,只是每组使用by而不是单个连接。使用内置值.BY,您可以迭代bk的行,这些行被馈送到findInterval的第二个参数(vec)。

dt[, b := findInterval(y, c(unlist(bk[.BY, b1:b4]), Inf), rightmost.closed=FALSE), by=x]

返回

dt
    x  y b
 1: 1  1 1
 2: 1  5 3
 3: 1  9 3
 4: 1  3 2
 5: 1  7 3
 6: 2  2 1
 7: 2  6 3
 8: 2 10 4
 9: 2  4 2
10: 2  8 3
11: 3  3 1
12: 3  7 3
13: 3  1 1
14: 3  5 2
15: 3  9 3
16: 4  4 2
17: 4  8 3
18: 4  2 1
19: 4  6 2
20: 4 10 4