【问题标题】:R vlookup based on the closest numeric variableR vlookup 基于最接近的数值变量
【发布时间】:2021-07-01 16:33:51
【问题描述】:

我想在 R 中做类似于 vlookup 的事情,使用数值变量作为基础。

示例查找表:

> Value <- c(1,1.5,2,2.5,3,3.5,4,4.5,5)
> Code <- c("A","B","C","D","E","F","G","H","I")
> Lookup_Table <- data.frame(Value, Code)
> Lookup_Table
  Value Code
1   1.0    A
2   1.5    B
3   2.0    C
4   2.5    D
5   3.0    E
6   3.5    F
7   4.0    G
8   4.5    H
9   5.0    I

样本数据表:

> DataSample <- c(1.2,1,2.3,2.7,3.1,3,4.6,4.5,3.8)
> DataSample <- data.frame(DataSample)
> DataSample
  DataSample
1        1.2
2        1.0
3        2.3
4        2.7
5        3.1
6        3.0
7        4.6
8        4.5
9        3.8

所以从这个DataSample 值我想根据查找表值匹配相应的Code。如果我的值是例如1.2,我想将它四舍五入到查找表上最接近的值1.5。所以我希望得到1.5的对应代码。

我想要的输出是:

> DataSample
  DataSample Code
1        1.2    B
2        1.0    A
3        2.3    D
4        2.7    E
5        3.1    F
6        3.0    E
7        4.6    I
8        4.5    H
9        3.8    G

【问题讨论】:

    标签: r merge vlookup intervals


    【解决方案1】:

    这里我用data.table来:

    1. 在查找表中创建间隔
    2. 应用foverlaps函数进行合并
    value <- c(1,1.5,2,2.5,3,3.5,4,4.5,5)
    code <- c("A","B","C","D","E","F","G","H","I")
    Lookup_Table <- data.frame(value, code)
    setDT(Lookup_Table)
    
    Lookup_Table <- Lookup_Table[order(value)]
    Lookup_Table[, previous.value := shift(value)]
    Lookup_Table[, next.value := shift(value, type = "lead")]
    Lookup_Table[, start := (previous.value + value) / 2]
    Lookup_Table[, end := (next.value + value) / 2]
    Lookup_Table[is.na(start), start := value]
    Lookup_Table[is.na(end), end := value]
    Lookup_Table <- Lookup_Table[, .(start, end, value, code)]
    setkey(Lookup_Table, start, end)
    
    DataSample <- data.frame(value = c(1.2,1,2.3,2.7,3.1,3,4.6,4.5,3.8))
    setDT(DataSample)
    DataSample[, start := value]
    DataSample[, end := value]
    DataSample <- DataSample[, .(start, end, value)]
    setkey(DataSample, start, end)
    
    
    res <- foverlaps(
      DataSample, 
      Lookup_Table, 
      by.x = c("start", "end"),
      by.y = c("start", "end")
    )
    
    res <- res[, .(value = i.value, code)]
    
    > res
    #   value code
    # 1:   1.0    A
    # 2:   1.2    A
    # 3:   2.3    D
    # 4:   2.7    D
    # 5:   3.0    E
    # 6:   3.1    E
    # 7:   3.8    G
    # 8:   4.5    H
    # 9:   4.6    H
    
    

    结果略有不同,您可能想尝试一下如何定义和应用范围

    【讨论】:

      【解决方案2】:

      基本的 R 方法可以像这样使用findInterval

      DataSample$Code <- with(Lookup_Table, 
                              Code[findInterval(DataSample$DataSample, Value, left.open = T) + 1]) 
      

      输出

        DataSample Code
      1        1.2    B
      2        1.0    A
      3        2.3    D
      4        2.7    E
      5        3.1    F
      6        3.0    E
      7        4.6    I
      8        4.5    H
      9        3.8    G
      

      【讨论】:

      • 出色的findInterval 方法,点赞!
      【解决方案3】:

      data.table 选项与non-equi join

      setorder(
        setDT(Lookup_Table),
        "Value"
      )[setDT(DataSample),
        on = .(Value >= DataSample)
      ][
        ,
        .(Code = first(Code)), .(DataSample = Value)
      ]
      

      给了

         DataSample Code
      1:        1.2    B
      2:        1.0    A
      3:        2.3    D
      4:        2.7    E
      5:        3.1    F
      6:        3.0    E
      7:        4.6    I
      8:        4.5    H
      9:        3.8    G
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-10
        • 1970-01-01
        • 1970-01-01
        • 2021-07-08
        • 2022-01-03
        • 2017-09-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多