首页 > 解决方案 > 在 R 中查找具有相同列类别的数据框中的上一个日期

问题描述

我有以下数据框:

      Date.POSIXct       Date      WeekDay DayCategory Hour Holidays   value
1 2018-05-01 00:00:00 2018-05-01      MA    MA-MI-JU    0        0      30
2 2018-05-01 01:00:00 2018-05-01      MA    MA-MI-JU    1        0      80
3 2018-05-01 02:00:00 2018-05-01      MA    MA-MI-JU    2        0      42
4 2018-05-01 03:00:00 2018-05-01      MA    MA-MI-JU    3        0      90
5 2018-05-01 04:00:00 2018-05-01      MA    MA-MI-JU    4        0      95
6 2018-05-01 05:00:00 2018-05-01      MA    MA-MI-JU    5        0       5

DayCategory 按以下方式对一周中的几天进行分组:Mondays 转到LUDayCategory。周二、周三和周四转到MA-MI-JUDayCategory。周五转至VI,周六转至SA,周日转至DO类别。

我想在前一天 ( )中找到value相同的相同,而仍然在同一组中(例如,如果一个实例有0,但前一天相同有 1,我们应该查找前一个,等等。 )hourDateDayCategoryHolidaysholidayDayCategory

作为中间步骤并了解该过程,我想添加一个PreviousDaySameDayCategoryDate前一天具有相同DayCategory对应行的列。有时它会date减去 7 天(“LU”、“VI”、“SA”、“DO”),但其他日子只会是 1 天。

可重现的数据:

library(lubridate)
Date.POSIXct <- seq(as.POSIXct("2018-05-01"), as.POSIXct("2018-05-31"), "hour")
mydf <- as.data.frame(Date.POSIXct)
mydf$Date <- as.Date(substr(as.character(mydf$Date.POSIXct),1,10))
mydf$WeekDay <- substr(toupper((weekdays(mydf$Date))),1,2)
mydf$DayCategory <-as.factor(ifelse(mydf$WeekDay == "MA" | mydf$WeekDay == "MI" | mydf$WeekDay == "JU", 
                                    "MA-MI-JU", mydf$WeekDay))
mydf$Hour <- hour(mydf$Date.POSIXct)
mydf$Holidays <- c(rep(0, 24*7),rep(1, 24*7), rep(0, 24*16+1))
set.seed(123)
mydf$myvalue <- sample.int(101,size=nrow(mydf),replace=TRUE)

我已经手动开始了第一天,并创建了一个解决方案应该是什么样子的向量:

  a <- rep(NA, 24)
  b <- mydf$value[1:24]
  c <- mydf$value[25:48]
  d <- rep(NA, 24)
  e <- rep(NA,24)
  f <- rep(NA,24)
  g <- rep(NA,24)
  h <- rep(NA,24)
  i <- mydf$value[169:192]
  solution <- c(a,b,c,d,e,f,g,h,i)
  solution

我将不胜感激思考过程中的任何提示,以解决我相对频繁面临的此类问题。

标签: rdataframedplyrdata.table

解决方案


这是一个data.table解决方案,它使用“分组shift()”和多个连接value从相同hourPreviousDaySameDayCategory.

创建可重现的数据

OP 创建可重现数据的代码不是完全可重现的,因为他使用了weekdays()返回当前语言环境中的工作日名称的函数(对于 OP 来说似乎是西班牙语)。为了独立于当前的语言环境,我切换到format(Date, "%u")返回数字 1 到 7 的星期一到星期日。此外,fct_collapse()fromforcats包用于将第 2 天、第 3 天和第 4 天(周二至周四)折叠为一个因子水平。

library(data.table)
# note that package lubridate is not required
myDT <- data.table(Date.POSIXct = seq(as.POSIXct("2018-05-01"), 
                                      as.POSIXct("2018-05-31"), "hour"))
myDT[, Date := as.Date(Date.POSIXct)]
myDT[, Weekday := format(Date, "%u")]
myDT[, DayCategory := forcats::fct_collapse(Weekday, "234" = c("2", "3", "4"))]
myDT[, hour := hour(Date.POSIXct)]
myDT[, Holidays := c(rep(0, 24 * 7), rep(1, 24 * 7), rep(0, 24 * 16 + 1))]
set.seed(123)
myDT[, myvalue := sample.int(101, size = nrow(mydf), replace = TRUE)]

中间步骤:PreviousDaySameDayCategory

样本数据集由每小时数据组成,但为了确定PreviousDaySameDayCategory我们需要每天工作,因此只需处理 、 和 的Date唯一DayCategoryHolidays。数据按DayCategoryHolidays指标分组。对于每个组,前一天由 lagging 选择Date。由于shift()操作的结果取决于数据集在移动之前已排序的行的顺序。

tmp <- unique(myDT[order(Date), .(Date, DayCategory, Holidays)])[
  , .(Date, PreviousDaySameDayCategory = shift(Date)), by = .(DayCategory, Holidays)][
    order(Date)]
tmp
    DayCategory Holidays       Date PreviousDaySameDayCategory
 1:         234        0 2018-05-01                       <NA>
 2:         234        0 2018-05-02                 2018-05-01
 3:         234        0 2018-05-03                 2018-05-02
 4:           5        0 2018-05-04                       <NA>
 5:           6        0 2018-05-05                       <NA>
 6:           7        0 2018-05-06                       <NA>
 7:           1        0 2018-05-07                       <NA>
 8:         234        1 2018-05-08                       <NA>
 9:         234        1 2018-05-09                 2018-05-08
10:         234        1 2018-05-10                 2018-05-09
11:           5        1 2018-05-11                       <NA>
12:           6        1 2018-05-12                       <NA>
13:           7        1 2018-05-13                       <NA>
14:           1        1 2018-05-14                       <NA>
15:         234        0 2018-05-15                 2018-05-03
16:         234        0 2018-05-16                 2018-05-15
17:         234        0 2018-05-17                 2018-05-16
18:           5        0 2018-05-18                 2018-05-04
19:           6        0 2018-05-19                 2018-05-05
20:           7        0 2018-05-20                 2018-05-06
21:           1        0 2018-05-21                 2018-05-07
22:         234        0 2018-05-22                 2018-05-17
23:         234        0 2018-05-23                 2018-05-22
24:         234        0 2018-05-24                 2018-05-23
25:           5        0 2018-05-25                 2018-05-18
26:           6        0 2018-05-26                 2018-05-19
27:           7        0 2018-05-27                 2018-05-20
28:           1        0 2018-05-28                 2018-05-21
29:         234        0 2018-05-29                 2018-05-24
30:         234        0 2018-05-30                 2018-05-29
31:         234        0 2018-05-31                 2018-05-30
    DayCategory Holidays       Date PreviousDaySameDayCategory

对于第 3 天和第 4 天(周三和周四),分别选择同一周的前一个周二和周三。对于第 2 天(星期二),如果两个星期都设置了相同的假期指示符,则选择前一周的前一个星期四。如果前一周有不同的假期指标,则选择同一假期的最近一个星期四。这就是为什么,例如,2018-05-03 在第 15 行中被选中。

value从匹配复制PreviousDaySameDayCategory

这分两步完成。PreviousDaySameDayCategory首先,通过加入匹配天数表从匹配中挑选小时值tmp

tmp2 <- myDT[tmp, on = .(Date = PreviousDaySameDayCategory), .(Date = i.Date, hour, myvalue), nomatch = 0L] 
tmp2
           Date hour myvalue
  1: 2018-05-02    0      30
  2: 2018-05-02    1      80
  3: 2018-05-02    2      42
  4: 2018-05-02    3      90
  5: 2018-05-02    4      95
 ---                        
500: 2018-05-31   19      39
501: 2018-05-31   20       1
502: 2018-05-31   21       1
503: 2018-05-31   22     101
504: 2018-05-31   23      11

其次,通过更新包含来自 的相应值的连接previousValuemyDT创建一个新列:PreviousDaySameDayCategory

myDT[tmp2, on = .(Date, hour), previousValue := i.myvalue]

这里显示了前两天的结果:

myDT[Date %between% c(as.Date("2018-05-01"), as.Date("2018-05-02"))]
           Date.POSIXct       Date Weekday DayCategory hour Holidays myvalue previousValue
 1: 2018-05-01 00:00:00 2018-05-01       2         234    0        0      30            NA
 2: 2018-05-01 01:00:00 2018-05-01       2         234    1        0      80            NA
 3: 2018-05-01 02:00:00 2018-05-01       2         234    2        0      42            NA
 4: 2018-05-01 03:00:00 2018-05-01       2         234    3        0      90            NA
 5: 2018-05-01 04:00:00 2018-05-01       2         234    4        0      95            NA
 6: 2018-05-01 05:00:00 2018-05-01       2         234    5        0       5            NA
 7: 2018-05-01 06:00:00 2018-05-01       2         234    6        0      54            NA
 8: 2018-05-01 07:00:00 2018-05-01       2         234    7        0      91            NA
 9: 2018-05-01 08:00:00 2018-05-01       2         234    8        0      56            NA
10: 2018-05-01 09:00:00 2018-05-01       2         234    9        0      47            NA
11: 2018-05-01 10:00:00 2018-05-01       2         234   10        0      97            NA
12: 2018-05-01 11:00:00 2018-05-01       2         234   11        0      46            NA
13: 2018-05-01 12:00:00 2018-05-01       2         234   12        0      69            NA
14: 2018-05-01 13:00:00 2018-05-01       2         234   13        0      58            NA
15: 2018-05-01 14:00:00 2018-05-01       2         234   14        0      11            NA
16: 2018-05-01 15:00:00 2018-05-01       2         234   15        0      91            NA
17: 2018-05-01 16:00:00 2018-05-01       2         234   16        0      25            NA
18: 2018-05-01 17:00:00 2018-05-01       2         234   17        0       5            NA
19: 2018-05-01 18:00:00 2018-05-01       2         234   18        0      34            NA
20: 2018-05-01 19:00:00 2018-05-01       2         234   19        0      97            NA
21: 2018-05-01 20:00:00 2018-05-01       2         234   20        0      90            NA
22: 2018-05-01 21:00:00 2018-05-01       2         234   21        0      70            NA
23: 2018-05-01 22:00:00 2018-05-01       2         234   22        0      65            NA
24: 2018-05-01 23:00:00 2018-05-01       2         234   23        0     101            NA
25: 2018-05-02 00:00:00 2018-05-02       3         234    0        0      67            30
26: 2018-05-02 01:00:00 2018-05-02       3         234    1        0      72            80
27: 2018-05-02 02:00:00 2018-05-02       3         234    2        0      55            42
28: 2018-05-02 03:00:00 2018-05-02       3         234    3        0      61            90
29: 2018-05-02 04:00:00 2018-05-02       3         234    4        0      30            95
30: 2018-05-02 05:00:00 2018-05-02       3         234    5        0      15             5
31: 2018-05-02 06:00:00 2018-05-02       3         234    6        0      98            54
32: 2018-05-02 07:00:00 2018-05-02       3         234    7        0      92            91
33: 2018-05-02 08:00:00 2018-05-02       3         234    8        0      70            56
34: 2018-05-02 09:00:00 2018-05-02       3         234    9        0      81            47
35: 2018-05-02 10:00:00 2018-05-02       3         234   10        0       3            97
36: 2018-05-02 11:00:00 2018-05-02       3         234   11        0      49            46
37: 2018-05-02 12:00:00 2018-05-02       3         234   12        0      77            69
38: 2018-05-02 13:00:00 2018-05-02       3         234   13        0      22            58
39: 2018-05-02 14:00:00 2018-05-02       3         234   14        0      33            11
40: 2018-05-02 15:00:00 2018-05-02       3         234   15        0      24            91
41: 2018-05-02 16:00:00 2018-05-02       3         234   16        0      15            25
42: 2018-05-02 17:00:00 2018-05-02       3         234   17        0      42             5
43: 2018-05-02 18:00:00 2018-05-02       3         234   18        0      42            34
44: 2018-05-02 19:00:00 2018-05-02       3         234   19        0      38            97
45: 2018-05-02 20:00:00 2018-05-02       3         234   20        0      16            90
46: 2018-05-02 21:00:00 2018-05-02       3         234   21        0      15            70
47: 2018-05-02 22:00:00 2018-05-02       3         234   22        0      24            65
48: 2018-05-02 23:00:00 2018-05-02       3         234   23        0      48           101
           Date.POSIXct       Date Weekday DayCategory hour Holidays myvalue previousValue

确认

结果符合OP的预期

identical(myDT[, previousValue[seq_along(solution)]], solution)
[1] TRUE

推荐阅读