簡體   English   中英

找到第二個數據幀中每個元素的兩個數據幀之間的最小距離

[英]Find the minimum distance between two data frames, for each element in the second data frame

我有兩個數據框ev1和ev2,描述了在許多測試中收集的兩種類型事件的時間戳。 因此,每個數據幀都有“test_id”和“timestamp”列。 我需要找到的是在同一測試中每個ev2的最小距離ev1。

我有一個工作代碼合並兩個數據集,計算距離,然后使用dplyr過濾最小距離:

ev1 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(1, 2, 3, 2, 3, 4))
ev2 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(6, 1, 8, 4, 5, 11))

data <- merge(ev2, ev1, by=c("test_id"), suffixes=c(".ev2", ".ev1"))

data$distance <- data$time.ev2 - data$time.ev1

min_data <- data %>%
  group_by(test_id, time.ev2) %>%
  filter(abs(distance) == min(abs(distance)))

雖然這有效,但合並部分非常慢並且感覺效率低下 - 我正在生成一個包含ev2-> ev1的所有組合的巨大表格,用於相同的test_id,僅將其過濾為1。 在合並期間,似乎應該有一種“即時過濾”的方法。 在那兒?

更新 :當使用akrun概述的data.table方法時,以下兩個“group by”列的情況會失敗:

ev1 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(1, 2, 3, 2, 3, 4), group_id=c(0, 0, 0, 1, 1, 1))
ev2 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(5, 6, 7, 1, 2, 8), group_id=c(0, 0, 0, 1, 1, 1))
setkey(setDT(ev1), test_id, group_id)
DT <- ev1[ev2, allow.cartesian=TRUE][,distance:=abs(time-i.time)]

eval(expr,envir,enclos)出錯:找不到對象'i.time'

這是我如何使用data.table做到這data.table

require(data.table)
setkey(setDT(ev1), test_id)
ev1[ev2, .(ev2.time = i.time, ev1.time = time[which.min(abs(i.time - time))]), by = .EACHI]
#    test_id ev2.time ev1.time
# 1:       0        6        3
# 2:       0        1        1
# 3:       0        8        3
# 4:       1        4        4
# 5:       1        5        4
# 6:       1       11        4

data.table中的形式x[i]data.table ,前綴為i. xi共享特定列的相同名稱時,用於引用i列。

請參閱此SO帖子 ,了解其工作原理。

這在語法上更容易理解正在發生的事情,並且內存有效(以低速1為代價),因為它根本沒有實現整個連接結果。 事實上,這正是你在帖子中所說的 - 在合並時動態過濾

  1. 速度上,在大多數情況下確實無關緊要。 如果i有很多行,則可能會慢一點,因為必須為i每一行計算j表達式。 相比之下,@ akrun的答案是笛卡爾連接,然后進行一次過濾。 因此,雖然它的內存很高,但它不會為i每一行計算j 但同樣,這甚至不應該重要,除非你使用非常大的 i ,而事實並非如此。

HTH

可能有幫助:

library(data.table)
setkey(setDT(ev1), test_id)
DT <- ev1[ev2, allow.cartesian=TRUE][,distance:=time-i.time]
DT[DT[,abs(distance)==min(abs(distance)), by=list(test_id, i.time)]$V1]
#    test_id time i.time distance
#1:       0    3      6        3
#2:       0    1      1        0
#3:       0    3      8        5
#4:       1    4      4        0
#5:       1    4      5        1
#6:       1    4     11        7

要么

 ev1[ev2, allow.cartesian=TRUE][,distance:= time-i.time][,
      .SD[abs(distance)==min(abs(distance))], by=list(test_id, i.time)]

更新

使用新的分組

setkey(setDT(ev1), test_id, group_id)
setkey(setDT(ev2), test_id, group_id)
DT <- ev1[ev2, allow.cartesian=TRUE][,distance:=i.time-time]
DT[DT[,abs(distance)==min(abs(distance)), by=list(test_id, 
                                group_id,i.time)]$V1]$distance
#[1]  2  3  4 -1  0  4

根據您提供的代碼

min_data$distance
#[1]  2  3  4 -1  0  4

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM