[英]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.