【问题标题】:Approximate matching近似匹配
【发布时间】:2017-05-05 10:02:26
【问题描述】:

我对 R 很陌生,我一直想知道是否存在用于近似 (dateTime) 匹配的函数或包。 intersect() 函数提供了完全匹配的列表,但我对近似匹配感兴趣。

例如我有两个具有 dateTime 值的数组,并且我想要两个数组中出现的事件列表,最大相差 2 秒。

arrayA<-c("2000-12-31 10:00:00","2000-12-31 12:00:00")
arrayB<-c("2000-12-31 10:00:00","2000-12-31 12:00:01")
arrayA<-strptime(arrayA, "%Y-%m-%d %H:%M:%S", tz="UTC")
arrayB<-strptime(arrayB, "%Y-%m-%d %H:%M:%S", tz="UTC")

intersect(arrayA,arrayB) #returns "2000-12-31 10:00:00 UTC" 

intersect() 只返回完全相同的值,但我想返回“2000-12-31 10:00:00 UTC”和“2000-12-31 12:00” :00 UTC”。

所以基本上我的问题是您是否可以指定相交匹配出现的程度。我的问题与日期有关,但数值可能会遇到同样的问题。我的数据集很大,所以2个for循环手动匹配往往需要很长时间,相交真的很快。

【问题讨论】:

    标签: r


    【解决方案1】:

    data.table 包提供了两种方法:foverlaps() 函数和非等连接。两种方法都需要向数据添加帮助列

    创建数据

    arrayA <- anytime::utctime(c("2000-12-31 10:00:00", "2000-12-31 12:00:00", 
                                 "2000-12-31 12:00:05", "2000-12-31 12:00:10"), tz = "UTC")
    arrayB <- anytime::utctime(c("2000-12-31 10:00:00", "2000-12-31 12:00:01", 
                                 "2000-12-31 12:00:02", "2000-12-31 11:00:00"), tz = "UTC")
    

    请注意,这两个向量都属于 POSIXct 类,它比由 strptime() 函数创建的 POSIXlt 类更合适。此外,还添加了更多时间戳来测试不匹配。

    准备数据

    这两种方法的数据准备是相同的:

    # make data.tables
    library(data.table)   # version 1.10.4 used here
    A <- data.table(arrayA)
    B <- data.table(arrayB)
    
    # define tolerance = 2 * tol_half
    tol_half <- 1L # seconds
    
    # add helper columns
    A[, "copyA" := arrayA]
    A
    #                arrayA               copyA
    #1: 2000-12-31 10:00:00 2000-12-31 10:00:00
    #2: 2000-12-31 12:00:00 2000-12-31 12:00:00
    #3: 2000-12-31 12:00:05 2000-12-31 12:00:05
    #4: 2000-12-31 12:00:10 2000-12-31 12:00:10
    
    B[, `:=`(start = arrayB - tol_half, end = arrayB + tol_half)]
    B
    #                arrayB               start                 end
    #1: 2000-12-31 10:00:00 2000-12-31 09:59:59 2000-12-31 10:00:01
    #2: 2000-12-31 12:00:01 2000-12-31 12:00:00 2000-12-31 12:00:02
    #3: 2000-12-31 12:00:02 2000-12-31 12:00:01 2000-12-31 12:00:03
    #4: 2000-12-31 11:00:00 2000-12-31 10:59:59 2000-12-31 11:00:01
    

    B 中的startend 表示arrayA 必须适合才能被视为匹配的可容忍时间范围。这类似于match_fun 函数在fuzzyjoin solution 中即时执行的操作。

    foverlaps()

    使用foverlaps() 搜索AB 中的重叠时间范围:

    # setting keys is required by foverlap()
    setkey(A, arrayA, copyA)
    setkey(B, start, end)
    
    # find overlaps
    result <- foverlaps(B, A, nomatch = 0)[, c("copyA", "start", "end") := NULL][]
    result
    #                arrayA              arrayB
    #1: 2000-12-31 10:00:00 2000-12-31 10:00:00
    #2: 2000-12-31 12:00:00 2000-12-31 12:00:01
    

    请注意,[, c("copyA", "start", "end") := NULL][] immediatley 会从 foverlaps() 的输出中删除辅助列。

    非等值连接

    使用最新版本的data.table非等值连接是可能的:

    result <- A[B, .(arrayA, arrayB), on = c("copyA>=start", "copyA<=end"), nomatch = 0L]
    result
    #                arrayA              arrayB
    #1: 2000-12-31 10:00:00 2000-12-31 10:00:00
    #2: 2000-12-31 12:00:00 2000-12-31 12:00:01
    

    请注意,由于自动索引,非 equi 连接不需要预先设置键。

    基准测试

    TO DO:在大型用例上比较 fuzzyjoinfoverlaps()非等值连接会很有趣。

    【讨论】:

      【解决方案2】:
      library(lubridate)
      library(fuzzyjoin)
      arrayA<-c("2000-12-31 10:00:00","2000-12-31 12:00:00")
      arrayB<-c("2000-12-31 10:00:00","2000-12-31 12:00:01")
      arrayA <- strptime(arrayA, "%Y-%m-%d %H:%M:%S", tz = "UTC")
      arrayB <- strptime(arrayB, "%Y-%m-%d %H:%M:%S", tz = "UTC")
      
      # make data frames for join operations
      A <- as.data.frame(arrayA)
      B <- as.data.frame(arrayB)
      
      # fuzzyjoin works by matching rows where a function applied
      # to the column pairs is TRUE. Here the function is defined 
      # inline, and uses lubridate durations.
      fuzzy_join(A, B, 
                 by=c("arrayA" = "arrayB"), 
                 match_fun = function(x,y) {abs(x-y) <= duration(2, "seconds")})
      
      # arrayA              arrayB
      # 1 2000-12-31 10:00:00 2000-12-31 10:00:00
      # 2 2000-12-31 12:00:00 2000-12-31 12:00:01
      

      【讨论】:

        猜你喜欢
        • 2011-05-11
        • 1970-01-01
        • 1970-01-01
        • 2010-12-28
        • 2013-07-10
        • 1970-01-01
        • 1970-01-01
        • 2013-01-27
        • 2020-01-11
        相关资源
        最近更新 更多