从另一个 data.table 中查找间隔 - 按组
Look up intervals from another data.table - by group
我有一个由 3 个部分组成的 A 部分。
首先,我描述了我成功地做到了这一点。
那我是怎么加多Part都不成功的。
章节长度在 data.table
d1
.
library(data.table)
d1 <- data.table(
Part="A",
Section=1:3,
SecLen=c(10,30,9))
d1
# Part Section SecLen
# 1: A 1 10
# 2: A 2 30
# 3: A 3 9
我在 d2
的部分也有一组位置。
d2 <- data.table(
Part="A",
PartLoc=c(0,7.5,10,20,35,45,49))
d2
# Part PartLoc
# 1: A 0.0
# 2: A 7.5
# 3: A 10.0
# 4: A 20.0
# 5: A 35.0
# 6: A 45.0
# 7: A 49.0
我想添加每个位置所在的部分。
首先,我使用 cumsum
在 d1
中堆叠部分长度
d1[,CumLen:=cumsum(SecLen)]
d1
# Part Section SecLen CumLen
# 1: A 1 10 10
# 2: A 2 30 40
# 3: A 3 9 49
然后我使用findInterval
来映射Section。请注意,我希望将位置 10 分配给第 1 部分,而不是第 2 部分。
d2[,Sec.fI:=findInterval(PartLoc,c(-1,d1$CumLen),left.open=TRUE)]
d2
# Part PartLoc Sec.fI
# 1: A 0.0 1
# 2: A 7.5 1
# 3: A 10.0 1
# 4: A 20.0 2
# 5: A 35.0 2
# 6: A 45.0 3
# 7: A 49.0 3
另一种方法使用 data.table
连接。
首先我添加每个部分的开始位置。
d1[,CumLen0:=c(-1,head(CumLen,-1))]
d1
# Part Section SecLen CumLen CumLen0
# 1: A 1 10 10 -1
# 2: A 2 30 40 10
# 3: A 3 9 49 40
然后查找该部分。
d2[,Sec.cs:=d1[d2,Section,on=.(CumLen0<PartLoc,CumLen>=PartLoc)]]
d2
# Part PartLoc Sec.fI Sec.cs
# 1: A 0.0 1 1
# 2: A 7.5 1 1
# 3: A 10.0 1 1
# 4: A 20.0 2 2
# 5: A 35.0 2 2
# 6: A 45.0 3 3
# 7: A 49.0 3 3
两种方法都行。
现在我尝试使用更多的零件。
D1 <- data.table(
Part = c("A","A","A","B","B","C"),
Section = c(1,2,3,1,2,1),
SecLen = c(10,30,9,5,20,18) # incorrectly had 10 for the last value
)
D2 <- data.table(
Part = c(rep("A",7),rep("B",3),rep("C",3)),
PartLoc = c(0.0,7.5,10,20,35,45,49,1,12,25,0,9,18)
)
D1[,CumLen:=cumsum(SecLen),by=Part]
D1
# Part Section SecLen CumLen
# 1: A 1 10 10
# 2: A 2 30 40
# 3: A 3 9 49
# 4: B 1 5 5
# 5: B 2 20 25
# 6: C 1 18 18
D2
# Part PartLoc
# 1: A 0.0
# 2: A 7.5
# 3: A 10.0
# 4: A 20.0
# 5: A 35.0
# 6: A 45.0
# 7: A 49.0
# 8: B 1.0
# 9: B 12.0
# 10: B 25.0
# 11: C 0.0
# 12: C 9.0
# 13: C 18.0
我试试findInterval
.
D2[,Sec.fI:=findInterval(PartLoc,c(-1,D1$CumLen),left.open=TRUE),by=Part]
# Error in findInterval(PartLoc, c(-1, D1$CumLen), left.open = TRUE) :
# 'vec' must be sorted non-decreasingly and not contain NAs
显然它不起作用,因为我没有按部分分组 D1$CumLen
,所以它是非递减的。
我试试加入。
D1[,CumLen0:=c(-1,head(CumLen,-1)),by=Part]
D2[,Sec.cs:=D1[D2,Section,on=.(CumLen0<PartLoc,CumLen>=PartLoc),by=Part]]
# Error in vecseq(f__, len__, if (allow.cartesian || notjoin || !anyDuplicated(f__, :
# Join results in 31 rows; more than 19 = nrow(x)+nrow(i).
# Check for duplicate key values in i each of which join to the same group in x over and over again.
# If that's ok, try by=.EACHI to run j for each group to avoid the large allocation.
# If you are sure you wish to proceed, rerun with allow.cartesian=TRUE.
# Otherwise, please search for this error message in the FAQ, Wiki, Stack Overflow and data.table issue tracker for advice.
在这里,我 运行 进入了我对联接的新生知识的极限。我按照建议尝试 allow.cartesian=TRUE
,但我只是确认我以某种方式得到了 31 行,但没有我想要的。
D1[D2,Section,on=.(CumLen0<PartLoc,CumLen>=PartLoc),by=Part,allow.cartesian=TRUE]
# Part Section
# 1: A 1
# 2: A 1
# 3: A 1
# 4: A 2
# 5: A 2
# 6: A 3
# 7: A 3
# 8: A 1
# 9: A 2
# 10: A 2
# 11: A 1
# 12: A 1
# 13: A 2
# 14: B 1
# 15: B 2
# 16: B 2
# 17: B 2
# 18: B 1
# 19: B 2
# 20: B 2
# 21: B 1
# 22: B 2
# 23: B 2
# 24: C 1
# 25: C 1
# 26: C 1
# 27: C 1
# 28: C 1
# 29: C 1
# 30: C 1
# 31: C 1
# Part Section
如果能帮助我在 data.table
中工作,我将不胜感激。
编辑
我对@Ian Campbell 的 findInterval
解决方案感到满意。我仍然有兴趣了解如何使连接工作。
您可以使用 .BY
特殊符号对 D1
进行子集化:
library(data.table)
D2[,Sec.fI:=findInterval(PartLoc,c(-1,D1[Part == .BY,CumLen]),left.open=TRUE),by=Part][]
Part PartLoc Sec.fI
1: A 0.0 1
2: A 7.5 1
3: A 10.0 1
4: A 20.0 2
5: A 35.0 2
6: A 45.0 3
7: A 49.0 3
8: B 1.0 1
9: B 12.0 2
10: B 25.0 2
11: C 0.0 1
12: C 9.0 1
13: C 18.0 2
有关详细信息,请参阅 help("special-symbols")
。
你的 OP 有点迷失。至少基于前 3 句话,这里有一个使用 rolling join 的选项:
d1[, LastPage := cumsum(SecLen)]
d2[, Section :=
d1[.SD, on=.(Part, LastPage=PartLoc), roll=-Inf, Section]
]
输出:
Part PartLoc Section
1: A 0.0 1
2: A 7.5 1
3: A 10.0 1
4: A 20.0 2
5: A 35.0 2
6: A 45.0 3
7: A 49.0 3
OP编辑:
我可以确认这对我的案例有更多的部分。
D2[, Sec.rJ :=
D1[.SD, on=.(Part, CumLen=PartLoc), roll=-Inf, Section]
][]
# Part PartLoc Sec.rJ
# 1: A 0.0 1
# 2: A 7.5 1
# 3: A 10.0 1
# 4: A 20.0 2
# 5: A 35.0 2
# 6: A 45.0 3
# 7: A 49.0 3
# 8: B 1.0 1
# 9: B 12.0 2
# 10: B 25.0 2
# 11: C 0.0 1
# 12: C 9.0 1
# 13: C 18.0 1
我有一个由 3 个部分组成的 A 部分。 首先,我描述了我成功地做到了这一点。 那我是怎么加多Part都不成功的。
章节长度在 data.table
d1
.
library(data.table)
d1 <- data.table(
Part="A",
Section=1:3,
SecLen=c(10,30,9))
d1
# Part Section SecLen
# 1: A 1 10
# 2: A 2 30
# 3: A 3 9
我在 d2
的部分也有一组位置。
d2 <- data.table(
Part="A",
PartLoc=c(0,7.5,10,20,35,45,49))
d2
# Part PartLoc
# 1: A 0.0
# 2: A 7.5
# 3: A 10.0
# 4: A 20.0
# 5: A 35.0
# 6: A 45.0
# 7: A 49.0
我想添加每个位置所在的部分。
首先,我使用 cumsum
d1
中堆叠部分长度
d1[,CumLen:=cumsum(SecLen)]
d1
# Part Section SecLen CumLen
# 1: A 1 10 10
# 2: A 2 30 40
# 3: A 3 9 49
然后我使用findInterval
来映射Section。请注意,我希望将位置 10 分配给第 1 部分,而不是第 2 部分。
d2[,Sec.fI:=findInterval(PartLoc,c(-1,d1$CumLen),left.open=TRUE)]
d2
# Part PartLoc Sec.fI
# 1: A 0.0 1
# 2: A 7.5 1
# 3: A 10.0 1
# 4: A 20.0 2
# 5: A 35.0 2
# 6: A 45.0 3
# 7: A 49.0 3
另一种方法使用 data.table
连接。
首先我添加每个部分的开始位置。
d1[,CumLen0:=c(-1,head(CumLen,-1))]
d1
# Part Section SecLen CumLen CumLen0
# 1: A 1 10 10 -1
# 2: A 2 30 40 10
# 3: A 3 9 49 40
然后查找该部分。
d2[,Sec.cs:=d1[d2,Section,on=.(CumLen0<PartLoc,CumLen>=PartLoc)]]
d2
# Part PartLoc Sec.fI Sec.cs
# 1: A 0.0 1 1
# 2: A 7.5 1 1
# 3: A 10.0 1 1
# 4: A 20.0 2 2
# 5: A 35.0 2 2
# 6: A 45.0 3 3
# 7: A 49.0 3 3
两种方法都行。
现在我尝试使用更多的零件。
D1 <- data.table(
Part = c("A","A","A","B","B","C"),
Section = c(1,2,3,1,2,1),
SecLen = c(10,30,9,5,20,18) # incorrectly had 10 for the last value
)
D2 <- data.table(
Part = c(rep("A",7),rep("B",3),rep("C",3)),
PartLoc = c(0.0,7.5,10,20,35,45,49,1,12,25,0,9,18)
)
D1[,CumLen:=cumsum(SecLen),by=Part]
D1
# Part Section SecLen CumLen
# 1: A 1 10 10
# 2: A 2 30 40
# 3: A 3 9 49
# 4: B 1 5 5
# 5: B 2 20 25
# 6: C 1 18 18
D2
# Part PartLoc
# 1: A 0.0
# 2: A 7.5
# 3: A 10.0
# 4: A 20.0
# 5: A 35.0
# 6: A 45.0
# 7: A 49.0
# 8: B 1.0
# 9: B 12.0
# 10: B 25.0
# 11: C 0.0
# 12: C 9.0
# 13: C 18.0
我试试findInterval
.
D2[,Sec.fI:=findInterval(PartLoc,c(-1,D1$CumLen),left.open=TRUE),by=Part]
# Error in findInterval(PartLoc, c(-1, D1$CumLen), left.open = TRUE) :
# 'vec' must be sorted non-decreasingly and not contain NAs
显然它不起作用,因为我没有按部分分组 D1$CumLen
,所以它是非递减的。
我试试加入。
D1[,CumLen0:=c(-1,head(CumLen,-1)),by=Part]
D2[,Sec.cs:=D1[D2,Section,on=.(CumLen0<PartLoc,CumLen>=PartLoc),by=Part]]
# Error in vecseq(f__, len__, if (allow.cartesian || notjoin || !anyDuplicated(f__, :
# Join results in 31 rows; more than 19 = nrow(x)+nrow(i).
# Check for duplicate key values in i each of which join to the same group in x over and over again.
# If that's ok, try by=.EACHI to run j for each group to avoid the large allocation.
# If you are sure you wish to proceed, rerun with allow.cartesian=TRUE.
# Otherwise, please search for this error message in the FAQ, Wiki, Stack Overflow and data.table issue tracker for advice.
在这里,我 运行 进入了我对联接的新生知识的极限。我按照建议尝试 allow.cartesian=TRUE
,但我只是确认我以某种方式得到了 31 行,但没有我想要的。
D1[D2,Section,on=.(CumLen0<PartLoc,CumLen>=PartLoc),by=Part,allow.cartesian=TRUE]
# Part Section
# 1: A 1
# 2: A 1
# 3: A 1
# 4: A 2
# 5: A 2
# 6: A 3
# 7: A 3
# 8: A 1
# 9: A 2
# 10: A 2
# 11: A 1
# 12: A 1
# 13: A 2
# 14: B 1
# 15: B 2
# 16: B 2
# 17: B 2
# 18: B 1
# 19: B 2
# 20: B 2
# 21: B 1
# 22: B 2
# 23: B 2
# 24: C 1
# 25: C 1
# 26: C 1
# 27: C 1
# 28: C 1
# 29: C 1
# 30: C 1
# 31: C 1
# Part Section
如果能帮助我在 data.table
中工作,我将不胜感激。
编辑
我对@Ian Campbell 的 findInterval
解决方案感到满意。我仍然有兴趣了解如何使连接工作。
您可以使用 .BY
特殊符号对 D1
进行子集化:
library(data.table)
D2[,Sec.fI:=findInterval(PartLoc,c(-1,D1[Part == .BY,CumLen]),left.open=TRUE),by=Part][]
Part PartLoc Sec.fI
1: A 0.0 1
2: A 7.5 1
3: A 10.0 1
4: A 20.0 2
5: A 35.0 2
6: A 45.0 3
7: A 49.0 3
8: B 1.0 1
9: B 12.0 2
10: B 25.0 2
11: C 0.0 1
12: C 9.0 1
13: C 18.0 2
有关详细信息,请参阅 help("special-symbols")
。
你的 OP 有点迷失。至少基于前 3 句话,这里有一个使用 rolling join 的选项:
d1[, LastPage := cumsum(SecLen)]
d2[, Section :=
d1[.SD, on=.(Part, LastPage=PartLoc), roll=-Inf, Section]
]
输出:
Part PartLoc Section
1: A 0.0 1
2: A 7.5 1
3: A 10.0 1
4: A 20.0 2
5: A 35.0 2
6: A 45.0 3
7: A 49.0 3
OP编辑:
我可以确认这对我的案例有更多的部分。
D2[, Sec.rJ :=
D1[.SD, on=.(Part, CumLen=PartLoc), roll=-Inf, Section]
][]
# Part PartLoc Sec.rJ
# 1: A 0.0 1
# 2: A 7.5 1
# 3: A 10.0 1
# 4: A 20.0 2
# 5: A 35.0 2
# 6: A 45.0 3
# 7: A 49.0 3
# 8: B 1.0 1
# 9: B 12.0 2
# 10: B 25.0 2
# 11: C 0.0 1
# 12: C 9.0 1
# 13: C 18.0 1