如何逐行使用另一个表中的which.min

时间:2018-12-03 05:35:45

标签: r dataframe min which

我尝试从另一个具有最小值的data.frame中获取数据。

有两种数据集,分别是card和log。

#    id      BSTN    ASTN    BSEC    ASEC
#    201557  151     150     60633   61302
#    201558  151     150     60159   60680
#    201559  151     150     44757   45149
#    201560  151     150     77551   77923
#    201561  151     150     61160   61606

日志

    TRNID   ASTN    TIME
#    1   150     45140
#    2   150     61300
#    3   150     61600
#    4   150     68570
#    5   150     77900
#    6   150     79125
#    7   150     82477
#    8   150     82767

我想要的是通过以下函数log [log.TRNID和log $ TIMElog $ TIME数据到卡数据中[log.min(card $ ASEC-log $ TIME)]

使用for循环,因为它逐行计算,所以花费的时间太长。有没有for循环的计算吗?

data.frame的最终结果如下:

#    id      BSTN    ASTN    BSEC    ASEC    TRNID   TIME
#    201557  151     150     60633   61302   2       61300
#    201558  151     150     60159   60680   2       61300
#    201559  151     150     44757   45149   1       45140
#    201560  151     150     77551   77923   5       77900
#    201561  151     150     61160   61606   3       61600

3 个答案:

答案 0 :(得分:2)

另一种方法是滚动联接:

library(data.table)
setDT(log)
setDT(card)

log[, ASEC := TIME]
res <- log[card, roll = -Inf, on = .(ASTN, ASEC)]

# >res
#
#    TRNID ASTN  TIME  ASEC     id BSTN  BSEC
# 1:     2  150 61350 61302 201557  151 60633
# 2:     2  150 61350 60680 201558  151 60159
# 3:     1  150 46140 45149 201559  151 44757
# 4:     5  150 77950 77923 201560  151 77551
# 5:     3  150 61650 61606 201561  151 61160

滚动连接将在log中为最后一个连接列(ASEC)的每个值在card中找到一个间隔。 -Inf表示log的下一个观察值将用于匹配card中的值。

答案 1 :(得分:1)

使用基数R的一种方法是,对于每个ASEC,我们在TIME中找到最小值log条目的索引,然后使用该索引返回相应的TRNIDTIME值并将其添加到card的原始数据帧中。

card[c("TRNID", "TIME")] <- do.call("rbind", lapply(card$ASEC, function(x) {
               inds <- log$TIME - x 
               idx <- which(inds %in% max(inds[inds < 0]))
               c(log$TRNID[idx], log$TIME[idx])
}))

card

#      id BSTN ASTN  BSEC  ASEC TRNID  TIME
#1 201557  151  150 60633 61302     2 61300
#2 201558  151  150 60159 60680     1 45140
#3 201559  151  150 44757 45149     1 45140
#4 201560  151  150 77551 77923     5 77900
#5 201561  151  150 61160 61606     3 61600

答案 2 :(得分:1)

由于您需要比较所有card$ASEClog$TIME之间的(绝对值)差异,因此我认为outer调用在这里最有用:

outer(card$ASEC, log$TIME, `-`)
#       [,1]   [,2]   [,3]   [,4]   [,5]   [,6]   [,7]   [,8]
# [1,] 15162    -48   -348  -7268 -16648 -17823 -21175 -21465
# [2,] 14540   -670   -970  -7890 -17270 -18445 -21797 -22087
# [3,]  -991 -16201 -16501 -23421 -32801 -33976 -37328 -37618
# [4,] 31783  16573  16273   9353    -27  -1202  -4554  -4844
# [5,] 15466    256    -44  -6964 -16344 -17519 -20871 -21161

我们可以快速减少(每行)该值,以找到最小绝对值:

( ind <- apply(abs(outer(card$ASEC, log$TIME, `-`)), 1, which.min) )
# [1] 2 2 1 5 3

cbind.data.frame(card, log[ind,], stringsAsFactors=FALSE)
#         id BSTN ASTN  BSEC  ASEC TRNID ASTN  TIME
# 2   201557  151  150 60633 61302     2  150 61350
# 2.1 201558  151  150 60159 60680     2  150 61350
# 1   201559  151  150 44757 45149     1  150 46140
# 5   201560  151  150 77551 77923     5  150 77950
# 3   201561  151  150 61160 61606     3  150 61650