基本上,我有以下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
,breaks
,c
,list
函数的各种组合来传递正确的unlist
参数,但没有运气。任何帮助/见解将不胜感激。谢谢!
完全披露,我是R的新手,这是我要发帖的第一篇文章。
答案 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.table
将bk
数据集重组为更简单的形式:
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