从另一个data.table中查找区间--按组查找。

问题描述 投票:0回答:1

我有一个由3个部分组成的A部分.首先,我描述了我成功地做了什么,然后我是如何不成功的更多的部分。

节的长度为 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  

我想添加每个位置所在的节。

首先,我将章节长度堆叠在 d1 使用 cumsum

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 来映射该部分。请注意,我希望位置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 加入。

首先我把每个Section的起始位置添加进去。

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

然后查找Section。

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

两种方式都可以。

现在我尝试用更多的Part。

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 由Part,所以它是非递减的。

我尝试连接。

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.

编辑我很满意 findInterval 由@Ian Campbell提出的解决方案。我还是有兴趣看看如何让加入工作。

r data.table intervals
1个回答
1
投票

你可以将 D1 随着 .BY 特殊符号。

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") 以获取更多信息。


1
投票

在你的OP中有点迷茫。至少基于前3句话,这里有一个使用滚动连接的选项。

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
© www.soinside.com 2019 - 2024. All rights reserved.