如何使用 data.table 函数根据规范调整代码功能

How adjust code functionality to specifications using data.table function

我想更改生成 Output 的方法。是否可以在下面的这种情况下使用 data.table 函数?如果是的话,你能帮我调整一下吗?我在下面插入了一个已完成计算的示例。下面的代码来自一个已经解决的问题:

library(dplyr)
library(tidyverse)
library(lubridate)


df1 <- structure(list(date1 = c("2021-06-28"), 
                      date2 = c("2021-06-30"), 
                      Category = c("FDE"), 
                      Week = c("Wednesday"), 
                      DR1 = c(4), DRM001 = c(4), DRM002 = c(2), 
                      DRM003 = c(9), DRM004 = c(5), DRM005 = c(5), 
                      DRM006 = c(2),DRM007 = c(1),
                      coef = c(8)), class = "data.frame", row.names = c(NA, -1L))


Output<-df1 %>% 
  mutate(across(starts_with("DR"), ~ coef - .),
         across(contains("date"), ymd),
         datedif = parse_number(as.character(date2-date1))
  ) %>% 
  rename_with(~str_replace(.,'(?<=[A-Z])0+(?=.)', ""),starts_with('DR')) %>% 
  rowwise %>%
  mutate(Result = if (str_c('DRM', datedif) %in% names(.)) get(str_c('DRM', datedif)) else coef) %>%
  ungroup() %>% 
  select(coef, Result)%>%data.frame()

> Output
  coef Result
1    8      6

例如:看到coef是8,date1date2的差是2,所以Result等于coef - DRM2。如果日期之间的差异是 3 那么它将是 Result = coef - DRM3

   date1      date2     Category  Week     DR1 DRM1 DRM2 DRM3 DRM4 DRM5 DRM6 DRM7 coef datedif
1 2021-06-28 2021-06-30  FDE    Wednesday   4    4    6   -1    3    3    6    7    8       2

检查:

  df1<-structure(list(Id = 8, date1 = structure(19090L, class = c("IDate", 
"Date")), date2 = structure(19090L, class = c("IDate", 
"Date")), Week = "Sexta-feira", DT = "0", Category = "PUBBAR", 
    GR = 1, DR1 = 14, DayM = 1, DayM1 = 1, DayM2 = 0, 
    DayM3 = 0, DayM4 = 1, DayM5 = 1, DayM6 = 1, DayM7 = 2, DayM8 = 2, 
    DayM9 = 2, DayM10 = 2, DayM11 = 4, DayM12 = 4, DayM13 = 4, 
    DayM14 = 4, DayM15 = 4, DayM16 = 4, DayM17 = 4, DayM18 = 4, 
    DayM19 = 4, DayM20 = 6, DayM21 = 6, DayM22 = 8, DayM23 = 8, 
    DayM24 = 8, DayM25 = 8, DayM26 = 8, DayM27 = 8, DayM28 = 8, 
    DayM29 = 8, DayM30 = 8, DayM31 = 10, DayM32 = 10, DayM33 = 10, 
    DayM34 = 10, DayM35 = 10, DayM36 = 10, DayM37 = 9, DayM38 = 9, 
    DayM39 = 9, DayM40 = 9, DayM41 = 9, DayM42 = 9, DayM43 = 9, 
    DayM44 = 9, DayM45 = 9, DayM46 = 9, DayM47 = 9, DayM48 = 9, 
    DayM49 = 9, DayM50 = 10, DayM51 = 10, DayM52 = 10, DayM53 = 10, 
    DayM54 = 10, DayM55 = 10, DayM56 = 10, DayM57 = 10, DayM58 = 10, 
    DayM59 = 10, DayM60 = 10, DayM61 = 10, DayM62 = 10, DayM63 = 10, 
    DayM64 = 10, DayM65 = 10, DayM66 = 10, DayM67 = 10, DayM68 = 10, 
    DayM69 = 10, DayM70 = 10, DayM71 = 10, DayM72 = 10, DayM73 = 10, 
    DayM74 = 10, DayM75 = 10, DayM76 = 10, DayM77 = 10, DayM78 = 10, 
    DayM79 = 10, DayM80 = 10, DayM81 = 10, DayM82 = 10, DayM83 = 10, 
    DayM84 = 10, DayM85 = 10, DayM86 = 10, DayM87 = 10, DayM88 = 10, 
    DayM89 = 10, DayM90 = 10, DayM91 = 10, DayM92 = 10, DayM93 = 10, 
    DayM94 = 10, DayM95 = 10, DayM96 = 10, DayM97 = 10, DayM98 = 10, 
    DayM99 = 10, DayM100 = 10, DayM101 = 10, DayM102 = 10, DayM103 = 10, 
    DayM104 = 10, DayM105 = 10, DayM106 = 10, DayM107 = 10, DayM108 = 10, 
    DayM109 = 10, DayM110 = 10, DayM111 = 10, DayM112 = 10, DayM113 = 10, 
    DayM114 = 10, DayM115 = 10, DayM116 = 10, DayM117 = 10, DayM118 = 10, 
    DayM119 = 10, DayM120 = 10, DayM121 = 10, DayM122 = 10, DayM123 = 10, 
    DayM124 = 10, DayM125 = 10, DayM126 = 10, DayM127 = 10, DayM128 = 10, 
    DayM129 = 10, DayM130 = 10, DayM131 = 12, DayM132 = 12, DayM133 = 12, 
    DayM134 = 12, DayM135 = 12, DayM136 = 12, DayM137 = 12, DayM138 = 12, 
    DayM139 = 12, DayM140 = 12, DayM141 = 12, DayM142 = 12, DayM143 = 12, 
    DayM144 = 12, DayM145 = 13, DayM146 = 13, DayM147 = 13, DayM148 = 13, 
    DayM149 = 13, DayM150 = 13, DayM151 = 13, DayM152 = 13, DayM153 = 14, 
    DayM154 = 14, DayM155 = 14, DayM156 = 14, DayM157 = 14, DayM158 = 14, 
    DayM159 = 14, DayM160 = 14, DayM161 = 14, DayM162 = 14, DayM163 = 14, 
    DayM164 = 14, DayM165 = 14, DayM166 = 14, DayM167 = 14, DayM168 = 14, 
    DayM169 = 14, DayM170 = 14, DayM171 = 14, DayM172 = 14, DayM173 = 14, 
    DayM174 = 14, DayM175 = 14, DayM176 = 14, DayM177 = 14, DayM178 = 14, 
    DayM179 = 14, DayM180 = 14, DayM181 = 14, DayM182 = 14, DayM183 = 14, 
    DayM184 = 14, DayM185 = 14, DayM186 = 14, DayM187 = 14, DayM188 = 14, 
    DayM189 = 14, DayM190 = 14, DayM191 = 14, DayM192 = 14, DayM193 = 14, 
    DayM194 = 14, DayM195 = 14, DayM196 = 14, DayM197 = 14, DayM198 = 14, 
    DayM199 = 14, DayM200 = 14, DayM201 = 14, DayM202 = 14, DayM203 = 14, 
    DayM204 = 14, DayM205 = 14, DayM206 = 14, DayM207 = 14, DayM208 = 14, 
    DayM209 = 14, DayM210 = 14, DayM211 = 14, DayM212 = 14, DayM213 = 14, 
    DayM214 = 14, DayM215 = 14, DayM216 = 14, DayM217 = 14, DayM218 = 14, 
    DayM219 = 14, DayM220 = 14, DayM221 = 14, DayM222 = 14, DayM223 = 14, 
    DayM224 = 14, DayM225 = 14, DayM226 = 14, DayM227 = 14, DayM228 = 14, 
    DayM229 = 14, DayM230 = 14, DayM231 = 14, DayM232 = 14, DayM233 = 14, 
    DayM234 = 14, DayM235 = 14, DayM236 = 14, DayM237 = 14, DayM238 = 14, 
    DayM239 = 14, DayM240 = 14, DayM241 = 14, DayM242 = 14, DayM243 = 14, 
    DayM244 = 14, DayM245 = 14, DayM246 = 14, DayM247 = 14, DayM248 = 14, 
    DayM249 = 14, DayM250 = 14, DayM251 = 14, DayM252 = 14, DayM253 = 14, 
    DayM254 = 14, DayM255 = 14, DayM256 = 14, DayM257 = 14, DayM258 = 14, 
    DayM259 = 14, DayM260 = 14, DayM261 = 14, DayM262 = 14, DayM263 = 14, 
    DayM264 = 14, DayM265 = 14, DayM266 = 14, DayM267 = 14, DayM268 = 14, 
    DayM269 = 14, DayM270 = 14, DayM271 = 14, DayM272 = 14, DayM273 = 14, 
    DayM274 = 14, DayM275 = 14, DayM276 = 14, DayM277 = 14, DayM278 = 14, 
    DayM279 = 14, DayM280 = 14, DayM281 = 14, DayM282 = 14, DayM283 = 14, 
    DayM284 = 14, DayM285 = 14, DayM286 = 14, DayM287 = 14, DayM288 = 14, 
    DayM289 = 14, DayM290 = 14, DayM291 = 14, DayM292 = 14, DayM293 = 14, 
    DayM294 = 14, DayM295 = 14, DayM296 = 14, DayM297 = 14, DayM298 = 14, 
    DayM299 = 14, DayM300 = 14, DayM301 = 14, DayM302 = 14, DayM303 = 14, 
    DayM304 = 14, DayM305 = 14, DayM306 = 14, DayM307 = 14, DayM308 = 14, 
    DayM309 = 14, DayM310 = 14, DayM311 = 14, DayM312 = 14, DayM313 = 14, 
    DayM314 = 14, DayM315 = 14, DayM316 = 14, DayM317 = 14, DayM318 = 14, 
    DayM319 = 14, DayM320 = 14, DayM321 = 14, DayM322 = 14, DayM323 = 14, 
    DayM324 = 14, DayM325 = 14, DayM326 = 14, DayM327 = 14, DayM328 = 14, 
    DayM329 = 14, DayM330 = 14, DayM331 = 14, DayM332 = 14, DayM333 = 14, 
    DayM334 = 14, DayM335 = 14, DayM336 = 14, DayM337 = 14, DayM338 = 14, 
    DayM339 = 14, DayM340 = 14, DayM341 = 14, DayM342 = 14, DayM343 = 14, 
    DayM344 = 14, DayM345 = 14, DayM346 = 14, DayM347 = 14, DayM348 = 14, 
    DayM349 = 14, DayM350 = 14, DayM351 = 14, DayM352 = 14, DayM353 = 14, 
    DayM354 = 14, DayM355 = 14, DayM356 = 14, DayM357 = 14, DayM358 = 14, 
    DayM359 = 14, DayM360 = 14, DayM361 = 14, DayM362 = 14, DayM363 = 14, 
    DayM364 = 14, DayM365 = 14, coef = 14, datedif = 0L), class = "data.frame", row.names = c(NA, 
-1L))

df1<-as.data.table(df1)

Output2 <-  df1[,  .(coef, Result = fcoalesce(as.matrix(.SD)[cbind(.I,         match(paste0('DayM', datedif), names(.SD)))], coef)),       .SDcols = patterns("^DayM\d+")]

> Output2
   coef Result
1:   14     14

结果是 coef - DayM = 14 - 1 = 13

使用 data.table,我们可以将 .SDcols 指定为 select 'DR' 列或 'date_cols' 并将输出分配回那些,然后改为使用按行匹配,使用 row/column 索引提取值以创建 'Result'

library(data.table)
# get the column names that starts with DR
dr_names <- grep("^DR", names(df1), value = TRUE)
# get the columns that contains date as substring
date_names <- grep("date", names(df1), value = TRUE)
# setDT - converts the data.frame to data.table
# .SDcols - specify the dr_names, date_names, loop over those
# with lapply, apply the functions and assign (`:=`) back to 
# same columns
setDT(df1)[, (dr_names) := lapply(.SD, function(x) coef - x), .SDcols = dr_names
    ][, (date_names) := lapply(.SD, as.IDate), .SDcols = date_names
    ][, datedif := date2 - date1]
# rename with setnames
setnames(df1, dr_names, sub("([A-Z])0+", "\1", dr_names))

# Extract the corresponding 'DRM' column based on the value from 
# datediff and match it with the DRM column names
# using a row/column indexing 
# return the Result and coef columns 
Output2 <- df1[,  .(coef, Result = as.matrix(.SD)[cbind(.I, 
       match(paste0('DRM', datedif), names(.SD)))]), 
     .SDcols = patterns("^DRM\d+")]
Output2[is.na(Result), Result := coef]

-输出

> Output2
    coef Result
   <num>  <num>
1:     8      6