【问题标题】:Add new column to data.table using conditional lookup from another data.table using R使用 R 从另一个 data.table 进行条件查找,将新列添加到 data.table
【发布时间】:2021-11-27 13:50:12
【问题描述】:

我的data.table dt如下-

dt = structure(list(date = structure(c(18904L, 18904L, 18904L), class = c("IDate", 
"Date")), exp_date = structure(c(18915L, 19013L, 19377L), class = c("IDate", 
"Date")), days_remaining = c(11, 109, 473), year_remaining = c(0.0301369863013699, 
0.298630136986301, 1.2958904109589)), row.names = c(NA, -3L), class = c("data.table", 
"data.frame"))

    date   exp_date days_remaining year_remaining
    1: 2021-10-04 2021-10-15             11     0.03013699
    2: 2021-10-04 2022-01-21            109     0.29863014
    3: 2021-10-04 2023-01-20            473     1.29589041

对于表 dt,我想从利率表中添加一个名为 rates_dt 的费率列 这里是利率数据表rates_dt

rates_dt = structure(list(index = structure(c(18900, 18901, 18904, 18905, 
18906), tzone = "UTC", tclass = "Date", class = "Date"), `1_MO` = c(0.07, 
0.08, 0.09, 0.1, 0.06), `2_MO` = c(0.05, 0.04, 0.04, 0.04, 0.04
), `3_MO` = c(0.04, 0.04, 0.04, 0.04, 0.04), `6_MO` = c(0.05, 
0.05, 0.06, 0.06, 0.06), `1_YR` = c(0.09, 0.09, 0.09, 0.09, 0.1
), `2_YR` = c(0.28, 0.27, 0.27, 0.28, 0.3), `3_YR` = c(0.53, 
0.49, 0.52, 0.54, 0.55)), class = c("data.table", "data.frame"
), row.names = c(NA, -5L))

        index 1_MO 2_MO 3_MO 6_MO 1_YR 2_YR 3_YR
1: 2021-09-30 0.07 0.05 0.04 0.05 0.09 0.28 0.53
2: 2021-10-01 0.08 0.04 0.04 0.05 0.09 0.27 0.49
3: 2021-10-04 0.09 0.04 0.04 0.06 0.09 0.27 0.52
4: 2021-10-05 0.10 0.04 0.04 0.06 0.09 0.28 0.54
5: 2021-10-06 0.06 0.04 0.04 0.06 0.10 0.30 0.55

我想做的是,如果days_remainingdt 表中少于30 天,则添加一个rates 列,在rates_dt 表中查找1_MO 列。同样,如果 days_remaining 为 473(因为超过 365 天),则从 rates_dt 表中的 1_YR 列获取费率。 输出应该是这样的 -

             date   exp_date days_remaining year_remaining rates
    1: 2021-10-04 2021-10-15             11     0.03013699 0.09
    2: 2021-10-04 2022-01-21            109     0.29863014 0.04
    3: 2021-10-04 2023-01-20            473     1.29589041 0.09

在实际数据中,date 列将包含过去一年的所有日期。所以我正在寻找的解决方案应该使用date分组。

我曾尝试融化rates_dt,然后执行以下操作,但无法达到所需的解决方案-

dt[melted_rates_dt, on = c("date" = "index"), rates := value]

如果有人可以提供有关如何解决此问题的任何指示,我将不胜感激。

谢谢!

【问题讨论】:

  • 2_YR 的比率都不是 0.09,因此看起来您的预期输出不一致。你能澄清一下吗?
  • melted_rates_dt 只是melt(rates_dt, id.vars = "index")
  • 感谢您指出。 473 天的利息为 1_YR 利率,因为此利率适用于 1_YR 至 2_YR。因此 0.09 的利率是正确的。

标签: r data.table


【解决方案1】:

这是我的建议:

REPREX

library(data.table)

# Join between dt and rates_dt
z <- rates_dt[dt, on = .(index = date)][, c(1,9,10,11,2:8)]


# fill 'rates' column with multiple nested 'fifelse' (i.e. dedicated ifelse for data.table) and delete unnecessary columns
z[, `:=` (rates = fifelse (days_remaining <= 30, `1_MO`, 
                           fifelse(days_remaining > 30 & days_remaining <= 60, `2_MO`,
                                   fifelse(days_remaining > 60 & days_remaining <= 365, `3_MO`,
                                           fifelse(days_remaining > 365 & days_remaining <= 730, `1_YR`, `3_YR`)))),
          `1_MO` = NULL, `2_MO` = NULL, `3_MO` = NULL, `6_MO` = NULL, `1_YR` = NULL, `2_YR` = NULL, `3_YR` = NULL)]

reprex package (v2.0.1) 于 2021-10-07 创建

输出:

z
#>         index   exp_date days_remaining year_remaining rates
#> 1: 2021-10-04 2021-10-15             11     0.03013699  0.09
#> 2: 2021-10-04 2022-01-21            109     0.29863014  0.04
#> 3: 2021-10-04 2023-01-20            473     1.29589041  0.09

reprex package (v2.0.1) 于 2021-10-07 创建

【讨论】:

    【解决方案2】:

    我解决了如下-

    melted_rates_dt = melt(rates_dt, id.vars = "index")
    dt[, duration := fcase(days_remaining < 30, "1_MO",
                                days_remaining < 61, "2_MO",
                                days_remaining < 91, "3_MO",
                                days_remaining < 181, "6_MO",
                                days_remaining < 365, "1_YR",
                                days_remaining < 730, "2_YR",
                                days_remaining < 1095, "3_YR")]
        
    dt[melted_rates_dt, on = c("duration" = "variable", 
                               "date" = "index"), rates := value]
    

    【讨论】:

      【解决方案3】:

      我认为这是 findInterval 的一个很好的案例,并加入了融化的利率。

      library(lubridate)
      periodtxt <- c("1_MO", "2_MO", "3_MO", "6_MO", "1_YR", "2_YR", "3_YR")
      periodn <- c(1, 2, 3, 6, 12, 24, 36)
      dt[, period := mapply(function(dt, exp) periodtxt[findInterval(exp, dt %m+% months(c(0, periodn)))],
                            date, exp_date) ]
      #          date   exp_date days_remaining year_remaining period
      #        <IDat>     <IDat>          <num>          <num> <char>
      # 1: 2021-10-04 2021-10-15             11     0.03013699   1_MO
      # 2: 2021-10-04 2022-01-21            109     0.29863014   6_MO
      # 3: 2021-10-04 2023-01-20            473     1.29589041   2_YR
      

      从这里开始,

      melted_rates_dt <- melt(rates_dt, id.vars = "index", variable.name = "period", value.name = "rate")
      dt[melted_rates_dt, rate := rate, on = .(date == index, period)]
      #          date   exp_date days_remaining year_remaining period  rate
      #        <IDat>     <IDat>          <num>          <num> <char> <num>
      # 1: 2021-10-04 2021-10-15             11     0.03013699   1_MO  0.09
      # 2: 2021-10-04 2022-01-21            109     0.29863014   6_MO  0.06
      # 3: 2021-10-04 2023-01-20            473     1.29589041   2_YR  0.27
      

      (我仍然不确定您是如何从 2_YR 数据中获得 0.09 的,所以我按原样提供,直到我更好地了解您的第三行预期输出。)

      【讨论】:

      • 谢谢@r2evans,这是一个很好的解决方案。我认为您的意思是 36 个月而不是 3 年的 26 个月。
      • 哈哈,是的,错字。谢谢。
      • exp 是与mapply 一起使用的匿名函数的第二个参数,它采用第一个date 和第一个exp_date 并对它们进行处理;然后它对每个变量的第二个值做同样的事情,等等。
      • 不完全。 findInterval 有两个参数:数据(此处为exp)和一个切割箱向量。它会找到适合“bin”exp 的位置,这些 bin 是:现在、+1 个月、+2 个月、+3 个月等。findInterval 将返回periodtxt 内的整数索引。请参阅findInterval(1:10, c(0,3,6,10)) 以尝试了解那里发生了什么。
      • 好的。而已!由于您的澄清,我(终于!)弄清楚了。再次感谢您的耐心和善意。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 2022-11-22
      • 1970-01-01
      • 2015-01-10
      相关资源
      最近更新 更多