[英]Calculate difference in date between rows
我有一個data.table,我想在其中標記在給定組ID的先前條目的90天內的條目。 上下文是這些都是交易的購買信號。 因此,我不希望在90天的時間范圍內重復工作,因為我假設我持有該職位90天,因此已經買了一個職位(並且我不想重新啟動時鍾)。
所以我有:
library(data.table)
> dt <- data.table(id = c("A", "A", "A", "B", "B", "B", "C", "C", "C"), date = as.Date(c("2017-01-01", "2017-02-01", "2017-05-01", "2017-01-01", "2017-05-01", "2017-10-01", "2017-01-01", "2017-02-01", "2017-02-15")))
> dt
id date
1: A 2017-01-01
2: A 2017-02-01
3: A 2017-05-01
4: B 2017-01-01
5: B 2017-05-01
6: B 2017-10-01
7: C 2017-01-01
8: C 2017-02-01
9: C 2017-02-15
我想得到:
> dt2
id date with.90d
1: A 2017-01-01 FALSE
2: A 2017-02-01 TRUE
3: A 2017-05-01 FALSE
4: B 2017-01-01 FALSE
5: B 2017-05-01 FALSE
6: B 2017-10-01 FALSE
7: C 2017-01-01 FALSE
8: C 2017-02-01 TRUE
9: C 2017-02-15 TRUE
我覺得我應該可以使用.SD做到這一點,但我不太清楚。 謝謝你的幫助!
您可以使用difftime
:
# Data
library(data.table)
dt <- data.table(id = c("A", "A", "A", "B", "B", "B", "C", "C", "C"), date = as.Date(c("2017-01-01", "2017-02-01", "2017-05-01", "2017-01-01", "2017-05-01", "2017-10-01", "2017-01-01", "2017-02-01", "2017-02-15")))
# Difference in days
dt[, with.90d := as.numeric(difftime(date, shift(date), units = "days")) < 90, id]
dt[is.na(with.90d), with.90d := FALSE]
# id date with.90d
# 1: A 2017-01-01 FALSE
# 2: A 2017-02-01 TRUE
# 3: A 2017-05-01 TRUE
# 4: B 2017-01-01 FALSE
# 5: B 2017-05-01 FALSE
# 6: B 2017-10-01 FALSE
# 7: C 2017-01-01 FALSE
# 8: C 2017-02-01 TRUE
# 9: C 2017-02-15 TRUE
說明:
difftime()
計算時間差。 日期和按組( id
)計算的轉移日期之間的差額。 FALSE
( is.na()
) 聽起來您想與所有先前的交易進行比較,以確保當前的交易不在任何一次的90天內。 為此,您可以嘗試:
dt[order(id, date), with.90d := sapply(1:(.N), function(i) all(difftime(date[i], date[1:(i-1)], units = "days") < 90) & i != 1L), by = id]
dt
# id date with.90d
#1: A 2017-01-01 FALSE
#2: A 2017-02-01 TRUE
#3: A 2017-05-01 FALSE
#4: B 2017-01-01 FALSE
#5: B 2017-05-01 FALSE
#6: B 2017-10-01 FALSE
#7: C 2017-01-01 FALSE
#8: C 2017-02-01 TRUE
#9: C 2017-02-15 TRUE
這是在計算當前日期與所有先前日期(在該組內)的差額,並檢查所有這些差額是否少於90天。 如果> = 90,則將其標記為FALSE
。 請注意,我使用all()
返回邏輯,但是您可以使用min()
,這可能會更快。
您還可以使用基本r函數:
transform(dt,with.90days=unlist(by(dt$date,dt$id,function(x)c(F,cumsum(as.numeric(diff(x)))<90))))
id date with.90days
1: A 2017-01-01 FALSE
2: A 2017-02-01 TRUE
3: A 2017-05-01 FALSE
4: B 2017-01-01 FALSE
5: B 2017-05-01 FALSE
6: B 2017-10-01 FALSE
7: C 2017-01-01 FALSE
8: C 2017-02-01 TRUE
9: C 2017-02-15 TRUE
OP已要求 :
從每個組中的第一個觀察值X開始,我要標記距離X不到90天的任何其他觀察。然后對於第二天的觀察點,如果距離X大於90天,則將其稱為觀察值Y,我要標記任何觀察值Y后的90天內。重復。
如果我從預期結果中正確理解, with.90d
列中的FALSE
值表示90天的開始時間。
不幸的是, 下一個 90天時段的開始取決於前一個90天時段到期后下一次觀察的日期。 因此,我們不能使用固定的90天間隔(從每個組的第一個日期開始)。
我嘗試使用非等額聯接或滾動聯接來查找解決方案,但到目前為止,我最終還是采用了遞歸方法:
dt3[, with.90d := NA]
while (dt3[, any(is.na(with.90d))])
dt3[is.na(with.90d), cd := date - min(date), by = id][
is.na(with.90d) & cd == 0, with.90d := FALSE][
is.na(with.90d) & cd <= 90, with.90d := TRUE]
dt3
id date with.90d cd 1: A 2017-01-01 FALSE 0 days 2: A 2017-02-01 TRUE 31 days 3: A 2017-05-01 FALSE 0 days 4: B 2017-01-01 FALSE 0 days 5: B 2017-05-01 FALSE 0 days 6: B 2017-10-01 FALSE 0 days 7: C 2017-01-01 FALSE 0 days 8: C 2017-02-01 TRUE 31 days 9: C 2017-02-15 TRUE 45 days 10: D 2017-03-01 FALSE 0 days 11: D 2017-04-01 TRUE 31 days 12: D 2017-05-01 TRUE 61 days 13: D 2017-06-01 FALSE 0 days 14: D 2017-07-01 TRUE 30 days 15: D 2017-08-01 TRUE 61 days 16: E 2017-01-01 FALSE 0 days 17: E 2017-02-01 TRUE 31 days 18: E 2017-03-01 TRUE 59 days 19: E 2017-04-01 TRUE 90 days 20: E 2017-05-01 FALSE 0 days 21: E 2017-06-01 TRUE 31 days id date with.90d cd
請注意,我在OP的樣本數據集上附加了另外兩個組D
和E
,以便更好地驗證該方法。 另請注意,從D
組開始於2017-03-01
組D
和E
從2017-01-01
開始的結果有何不同。
只要with.90d
有NA
值, with.90d
只對NA
行重復以下順序(完成TRUE
或FALSE
值的行):
min(date)
還可與無序數據集一起使用。 或者,可以使用setorder(dt3, date)
和first(date)
(或date[1]
)。 0
表示新期間的開始,並標記為FALSE
。 TRUE
。 NA
值。 為了說明起見,我將helper列保留為cd
。 可以通過dt3[, cd := NULL]
將其刪除。
# OP's sample dataset
dt <- data.table(id = c("A", "A", "A", "B", "B", "B", "C", "C", "C"),
date = as.Date(c("2017-01-01", "2017-02-01", "2017-05-01", "2017-01-01", "2017-05-01", "2017-10-01", "2017-01-01", "2017-02-01", "2017-02-15")))
# append group D
dt2 <- dt[, .(id = c(id, rep("D", 6)),
date = c(date, seq(as.Date("2017-03-01"), length.out = 6, by = "1 month")))]
# append group E
dt3 <- dt2[, .(id = c(id, rep("E", 6)),
date = c(date, seq(as.Date("2017-01-01"), length.out = 6, by = "1 month")))]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.