Как использовать which.min из другой таблицы за строкой - PullRequest
0 голосов
/ 03 декабря 2018

Я пытаюсь получить данные из другого data.frame с минимальным значением.

Существует два вида наборов данных: карточка и журнал.

карточка

#    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

log

    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

То, что я хочу, это получить данные журнала $ TRNID и записать данные $ TIMElog $ TIME в данные карты с помощью следующей функции log [which.min (card $ ASEC-log $)ВРЕМЯ)]

С циклом 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 голосов
/ 03 декабря 2018

Поскольку вам необходимо сравнить (абсолютное значение) разницу между всеми card$ASEC и log$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
0 голосов
/ 03 декабря 2018

Другой способ - скользящее объединение:

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.

0 голосов
/ 03 декабря 2018

Один из способов использования базы R может быть следующим: для каждого ASEC мы находим индекс минимального значения TIME запись в log и, используя этот индекс, возвращаем соответствующее значение TRNID и TIME и добавляем его висходный кадр данных 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
...