【问题标题】:Map values to non-overlapping intervals将值映射到非重叠间隔
【发布时间】:2018-01-29 09:50:19
【问题描述】:

我有一组不重叠的间隔,每个间隔都有一个 ID。给定一个数字,我想根据它所属的间隔为其分配一个 ID(如果不存在这样的间隔,则为 NA)。

intervals_id <- structure(list(ID = c(851, 852, 999), Lower = c(85101, 85201, 
    85301), Upper = c(85104, 85206, 85699)), .Names = c("ID", "Lower", 
    "Upper"), row.names = c(NA, -3L), class = "data.frame")

#    ID Lower Upper
# 1 851 85101 85104
# 2 852 85201 85206
# 3 999 85301 85699

value <- c(15555, 85102, 85201, 85206, 85207, 85600, 86999)

我使用cut 整理了一些东西,它似乎有效,但感觉很乱。任何想法更优雅和直接的解决方案?

intervals_id <- intervals_id[order(intervals_id$Lower),]
intervals_id$UpperP <- intervals_id$Upper + 0.01
position <- as.numeric(cut(value, breaks = 
    as.numeric(t(as.matrix(intervals_id[,c("Lower", "UpperP")]))), right = FALSE))
position[position %% 2 == 0] <- NA
position <- (position + 1) %/% 2 

# desired result
data.frame(value, valueID = intervals_id$ID[position])

#   value valueID
# 1 15555      NA
# 2 85102     851
# 3 85201     852
# 4 85206     852
# 5 85207      NA
# 6 85600     999
# 7 86999      NA

【问题讨论】:

    标签: r


    【解决方案1】:

    您可以使用 data.table 包中的 foverlaps() 函数。它会发现两组区间之间的重叠。

    首先我们需要创建 data.table 并为它们设置键。

    library(data.table)
    
    # Using OPs data
    setDT(intervals_id)
    setkey(intervals_id, Lower, Upper)
    
    # Create dummy intervals (same coordinate) and set key
    valueDT <- data.table(start = value, end = value)
    setkey(valueDT, start, end)
    

    接下来,应用foverlaps()函数:

    foverlaps(valueDT, intervals_id)[, .(value = start, ID)]
    

    结果:

    #    value  ID
    # 1: 15555  NA
    # 2: 85102 851
    # 3: 85201 852
    # 4: 85206 852
    # 5: 85207  NA
    # 6: 85600 999
    # 7: 86999  NA
    

    PS。 foverlaps 输出如下所示:

        ID Lower Upper start   end
    1:  NA    NA    NA 15555 15555
    2: 851 85101 85104 85102 85102
    3: 852 85201 85206 85201 85201
    4: 852 85201 85206 85206 85206
    5:  NA    NA    NA 85207 85207
    6: 999 85301 85699 85600 85600
    7:  NA    NA    NA 86999 86999
    

    如果需要,您可以使用foverlaps 选项。

    • 使用nomatch 过滤掉没有重叠的区间
    • 使用mult 报告“所有”、“第一个”或“最后一个”重叠

    【讨论】:

      【解决方案2】:

      另一个data.table - baseR 混合使用data.table::between 可以,

      sapply(value, function(i) {i1 = df$ID[data.table::between(i, df$Lower, df$Upper)]; 
                                 if (length(i1) == 0){NA}else{i1}})
      
      #[1]  NA 851 852 852  NA 999  NA
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-14
        • 2010-11-15
        • 2012-03-19
        • 1970-01-01
        • 2017-06-09
        • 1970-01-01
        • 2014-11-29
        • 1970-01-01
        相关资源
        最近更新 更多