【问题标题】:Find last date of previous week using data.table in R使用 R 中的 data.table 查找前一周的最后日期
【发布时间】:2019-12-29 11:39:07
【问题描述】:

我有一个data.frame,如下图:

structure(list(Start_Date = c("D1", "D2", "D3", "D4", "NA", "NA", 
"D6", "D7"), Week = c("W1", "W1", "W1", "W2", "W2", "W3", "W4", 
"W4"), last_date = c(NA, NA, NA, "D3", "D3", "D4", "D4", "D4"
)), class = "data.frame", row.names = c(NA, -8L))

输出是列'last_date'

我需要什么? - 我想找到前一周的最后一个非 NA 日期。如果前一周只有 NA 日期,那么它应该查看前一周并找到非 NA 日期。 例如 - 对于 W2 的所有日期,最后一个日期将是 D3(上一周的最后一个非 NA 日期)。对于 W3,它应该返回 D4。 对于 W4,由于 W3 的最后一个日期是 NA,它应该寻找前一周的非 NA 日期(即 W2)并返回 D4。

总而言之,最后一个日期将是最近的非 NA 日期(不是来自本周)

由于我的数据集太庞大,我正在寻找 data.table 解决方案。

【问题讨论】:

标签: r data.table


【解决方案1】:

这是一个选项(假设数据已经排序):

# Load data.table and convert data.frame to data.table
library(data.table)
setDT(df)

# Clean data; "NA" is just a regular character at the moment
df[Start_Date == "NA", Start_Date := NA_character_]

# Step 1: Create a numeric week index
df[, week_nr := .GRP, keyby = Week]
# Step 2: Create a lookup table (lut) for last date for each week
lut <- df[!is.na(Start_Date), last(Start_Date), by = week_nr + 1L]
# Step 3: Use join syntax to "consult" the lut and add a new column
df[, last_dat2 := lut[.SD, on = "week_nr", V1, roll = Inf]] 

步骤 2-3 可以压缩为一个步骤:

df[, last_dat2 := df[!is.na(Start_Date)
                     ][.SD, 
                       on = .(week_nr < week_nr), 
                       last(Start_Date), 
                       by = .EACHI]$V1]

或者更简洁地使用mult=

df[, last_dat2 := df[!is.na(Start_Date)
                     ][.SD, 
                       on = .(week_nr < week_nr), 
                       Start_Date, 
                       mult = "last"]]

输出:

   Start_Date Week last_date week_nr last_dat2
1:         D1   W1      <NA>       1      <NA>
2:         D2   W1      <NA>       1      <NA>
3:         D3   W1      <NA>       1      <NA>
4:         D4   W2        D3       2        D3
5:       <NA>   W2        D3       2        D3
6:       <NA>   W3        D4       3        D4
7:         D6   W4        D4       4        D4
8:         D7   W4        D4       4        D4

【讨论】:

  • 嗨 Sindri..谢谢您的解决方案。但是,我在您的解决方案中发现了一个遗漏。根据您的解决方案,它只是将指针移动到前一周。如果前一周只有一个 NA 日期,那么它应该查看前一周并找出非 NA 日期。简而言之,最新的非 NA 日期(不是从本周开始)
【解决方案2】:

另一个data.table 选项是将roll=mult= 一起使用

setDT(DT)[, c("Week", "W") := .(rl <- rleid(Week), rl - 0.1)][, 
    last_dat := df[Start_Date!="NA"][
        .SD, on=.(Week=W), roll=Inf, mult="last", x.Start_Date]
    ]

有兴趣了解实际数据集的维度和统计数据,以便为差异解决方案计时。

输出:

   Start_Date Week last_date   W last_dat
1:         D1    1      <NA> 0.9     <NA>
2:         D2    1      <NA> 0.9     <NA>
3:         D3    1      <NA> 0.9     <NA>
4:         D4    2        D3 1.9       D3
5:         NA    2        D3 1.9       D3
6:         NA    3        D4 2.9       D4
7:         D6    4        D4 3.9       D4
8:         D7    4        D4 3.9       D4

数据:

library(data.table)
DT <- structure(list(Start_Date = c("D1", "D2", "D3", "D4", "NA", "NA", 
    "D6", "D7"), Week = c("W1", "W1", "W1", "W2", "W2", "W3", "W4", 
        "W4"), last_date = c(NA, NA, NA, "D3", "D3", "D4", "D4", "D4"
        )), class = "data.frame", row.names = c(NA, -8L))

【讨论】:

  • 我在我的解决方案中忘记了mult=
【解决方案3】:

这里,要加入的查找表是以不同的方式创建的:

library(data.table)
library(magrittr) # piping used to improve readability
lut <- DT[, .(Week, fifelse(Start_Date == "NA", NA_character_, Start_Date) %>% zoo::na.locf())][
  , last(V2), by = Week][
    , V1 := shift(V1)][]
DT[lut, on = .(Week),  last_date2 := V1][]
   Start_Date Week last_date last_date2
1:         D1   W1      <NA>       <NA>
2:         D2   W1      <NA>       <NA>
3:         D3   W1      <NA>       <NA>
4:         D4   W2        D3         D3
5:         NA   W2        D3         D3
6:         NA   W3        D4         D4
7:         D6   W4        D4         D4
8:         D7   W4        D4         D4

查找表是

lut
   Week   V1
1:   W1 <NA>
2:   W2   D3
3:   W3   D4
4:   W4   D4

创建者

  • 将缺失的Start_Date 值替换为以前的值(LOCF = 最后一次观察结转),
  • 需要事先将字符串"NA"替换为NA_character
  • Week聚合,
  • 最后将值移动(滞后)一周。

请注意,查找表不包含任何NA 值(当然第一行除外),并且W2 周的最后一个有效Start_Date D4 已结转至周W3W4

【讨论】:

    【解决方案4】:

    这是一个基本的 R 解决方案,其中使用了 ave()split()

    df$last_date <- df$last_date <- with(df, ave(na.omit(Start_Date)[cumsum(!is.na(Start_Date))],Week, FUN = function(x) tail(x[!is.na(x)],1)))
    dfout <- Reduce(rbind,
                    lapply(seq(dfs<-split(df,df$Week)), 
                           function(k) {
                             dfs[[k]]$last_date <- ifelse(k==1, NA, unique(dfs[[k-1]]$last_date)); 
                             dfs[[k]]}))
    

    这样

      Start_Date Week last_date
    1         D1   W1      <NA>
    2         D2   W1      <NA>
    3         D3   W1      <NA>
    4         D4   W2        D3
    5       <NA>   W2        D3
    6       <NA>   W3        D4
    7         D6   W4        D4
    8         D7   W4        D4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-01
      • 2023-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多