簡體   English   中英

計算行之間的日期差

[英]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 )計算的轉移日期之間的差額。
  • 檢查差異是否少於90天。
  • 為每個組的第一個日期插入FALSEis.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的樣本數據集上附加了另外兩個組DE ,以便更好地驗證該方法。 另請注意,從D組開始於2017-03-01DE2017-01-01開始的結果有何不同。

說明

只要with.90dNA值, with.90d 只對NA重復以下順序(完成TRUEFALSE值的行):

  • 計算到每個組中第一個日期的日差。 請注意,使用min(date)還可與無序數據集一起使用。 或者,可以使用setorder(dt3, date)first(date) (或date[1] )。
  • 時差為0表示新期間的開始,並標記為FALSE
  • 日差小於或等於90天的行被標記為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM