[英]Find last date of previous week using data.table in R
我有一个 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 日期。 例如 - 对于 W2 的所有日期,最后一个日期将是 D3(上周的最后一个非 NA 日期)。 对于 W3,它应该返回 D4。 对于 W4 ,因为只有 W3 的最后一个日期是 NA,它应该查找前一周(即 W2)的非 NA 日期并返回 D4。
总而言之,最后一个日期将是最近的非北美日期(不是来自本周)
由于我的数据集过于庞大,我正在寻找 data.table 解决方案。
这是一种选择(假设已经订购了数据):
# 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
另一个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))
在这里,要加入的查找表以不同的方式创建:
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 = Last Observation Carried Forward ),NA_character
替换字符串"NA"
,Week
聚合, 请注意,查找表不包含任何NA
值(当然,第一行除外),并且W2
周的最后一个有效Start_Date
D4
已结转到W3
和W4
周。
这是一个基本的 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.