dplyr mutate函数用于垂直计算列(当前,上一个,下一个)内的值

时间:2016-06-06 19:04:50

标签: r dplyr

我已经搜索了SO,以便在没有运气的情况下实现我的需要,所以在这里。 前段时间我发现了包装dplyr及其潜力。我认为这个包可以做我想要的,我只是不知道如何。这是我数据的一小部分,但应该代表我的问题。

    dummy<-structure(list(time = structure(1:20, .Label = c("2015-03-25 12:24:00", 
    "2015-03-25 21:08:00", "2015-03-25 21:13:00", "2015-03-25 21:47:00", 
    "2015-03-26 03:08:00", "2015-04-01 20:30:00", "2015-04-01 20:34:00", 
    "2015-04-01 20:42:00", "2015-04-01 20:45:00", "2015-09-29 18:26:00", 
    "2015-09-29 19:11:00", "2015-09-29 21:21:00", "2015-09-29 22:03:00", 
    "2015-09-29 22:38:00", "2015-09-30 00:48:00", "2015-09-30 01:38:00", 
    "2015-09-30 01:41:00", "2015-09-30 01:45:00", "2015-09-30 01:47:00", 
    "2015-09-30 01:49:00"), class = "factor"), ID = c(1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L), station = c(1L, 1L, 1L, 2L, 3, 
    4L, 4L, 4L, 4L, 5L, 5L, 6L, 
    6L, 5, 5, 5L, 7, 7, 7L, 
    7)), .Names = c("time", "ID", "station"), class = "data.frame", row.names = c(NA, 
    -20L))

我希望根据ID和station列来评估时间列中的行。具体来说,我希望函数(dplyr?)评估每个时间行,并将时间与前一个时间(第一行)和下一个时间(行+ 1)进行比较。如果当前行的时间在前一行和/或下一行的1小时之内,并且当前行的ID和站与上一行和/或下一行的ID和站匹配,那么我想在新行中添加一行1 ,否则为0。

我如何使用dplyr实现这一目标?

预期结果应该是这样的:

                  time ID station new.value
1  2015-03-25 12:24:00  1       1         0
2  2015-03-25 21:08:00  1       1         1
3  2015-03-25 21:13:00  1       1         1
4  2015-03-25 21:47:00  1       2         0
5  2015-03-26 03:08:00  1       3         0
6  2015-04-01 20:30:00  1       4         1
7  2015-04-01 20:34:00  1       4         1
8  2015-04-01 20:42:00  1       4         1
9  2015-04-01 20:45:00  1       4         1
10 2015-09-29 18:26:00  2       5         1
11 2015-09-29 19:11:00  2       5         1
12 2015-09-29 21:21:00  2       6         1
13 2015-09-29 22:03:00  2       6         1
14 2015-09-29 22:38:00  2       5         0
15 2015-09-30 00:48:00  2       5         1
16 2015-09-30 01:38:00  2       5         1
17 2015-09-30 01:41:00  2       7         1
18 2015-09-30 01:45:00  2       7         1
19 2015-09-30 01:47:00  2       7         1
20 2015-09-30 01:49:00  2       7         1

3 个答案:

答案 0 :(得分:5)

以下是使用difftimedplyr mutate函数的选项。首先,我们使用group_by操作来确保比较在ID和Station的每个唯一组合中。 difftime可用于计算差异时间,为方便起见,此处单位将设置为hourslaglead函数也来自dplyr包,它会向后或向前移动所选列。结合difftime的矢量化操作,您可以计算当前行与上一行/下一行之间的时差。我们使用abs来确保结果是绝对值。 <1的条件确保差异在一小时内。 as.integer相应地将逻辑值(T或F)转换为(1或0)。

library(dplyr)
dummy %>% group_by(ID, station) %>% 
          mutate(new.value = as.integer(
                 abs(difftime(time, lag(time, default = Inf), units = "hours")) < 1 | 
                 abs(difftime(time, lead(time, default = Inf), units = "hours")) < 1))

Source: local data frame [20 x 4]
Groups: ID, station [7]

                  time    ID station new.value
                (time) (int)   (dbl)     (int)
1  2015-03-25 12:24:00     1       1         0
2  2015-03-25 21:08:00     1       1         1
3  2015-03-25 21:13:00     1       1         1
4  2015-03-25 21:47:00     1       2         0
5  2015-03-26 03:08:00     1       3         0
6  2015-04-01 20:30:00     1       4         1
7  2015-04-01 20:34:00     1       4         1
8  2015-04-01 20:42:00     1       4         1
9  2015-04-01 20:45:00     1       4         1
10 2015-09-29 18:26:00     2       5         1
11 2015-09-29 19:11:00     2       5         1
12 2015-09-29 21:21:00     2       6         1
13 2015-09-29 22:03:00     2       6         1
14 2015-09-29 22:38:00     2       5         0
15 2015-09-30 00:48:00     2       5         1
16 2015-09-30 01:38:00     2       5         1
17 2015-09-30 01:41:00     2       7         1
18 2015-09-30 01:45:00     2       7         1
19 2015-09-30 01:47:00     2       7         1
20 2015-09-30 01:49:00     2       7         1

答案 1 :(得分:5)

Psidom的答案很棒 - 这是data.table方法。

library(data.table)
setDT(dummy)
# you do NOT want a factor for your time variable
dummy[, time := as.POSIXct(time) ]
dummy[, `:=`(lag_diff = c(Inf, diff(as.numeric(time))),
             lead_diff = c(diff(as.numeric(time)), Inf)),
      by = .(ID, station) ]
dummy[, new.value := as.integer(lag_diff < 3600 | lead_diff < 3600) ]
dummy

答案 2 :(得分:3)

使用R基函数(sapplydifftime)的另一种解决方案:

n=nrow(dummy)
dummy$new.value=
as.numeric(sapply(1:n, function(i) 
(i<n && (dummy[i,"ID"]==dummy[i+1,"ID"] && dummy[i,"station"]==dummy[i+1,"station"]) 
&& abs(as.numeric(difftime(dummy[i,"time"], dummy[i+1,"time"]), "hours"))<=1) 
|| 
(i>1 && (dummy[i,"ID"]==dummy[i-1,"ID"] && dummy[i,"station"]==dummy[i-1,"station"]) 
&& abs(as.numeric(difftime(dummy[i,"time"], dummy[i-1,"time"]), "hours"))<=1) 
))

# > dummy
                  # time ID station new.value
# 1  2015-03-25 12:24:00  1       1         0
# 2  2015-03-25 21:08:00  1       1         1
# 3  2015-03-25 21:13:00  1       1         1
# 4  2015-03-25 21:47:00  1       2         0
# 5  2015-03-26 03:08:00  1       3         0
# 6  2015-04-01 20:30:00  1       4         1
# 7  2015-04-01 20:34:00  1       4         1
# 8  2015-04-01 20:42:00  1       4         1
# 9  2015-04-01 20:45:00  1       4         1
# 10 2015-09-29 18:26:00  2       5         1
# 11 2015-09-29 19:11:00  2       5         1
# 12 2015-09-29 21:21:00  2       6         1
# 13 2015-09-29 22:03:00  2       6         1
# 14 2015-09-29 22:38:00  2       5         0
# 15 2015-09-30 00:48:00  2       5         1
# 16 2015-09-30 01:38:00  2       5         1
# 17 2015-09-30 01:41:00  2       7         1
# 18 2015-09-30 01:45:00  2       7         1
# 19 2015-09-30 01:47:00  2       7         1
# 20 2015-09-30 01:49:00  2       7         1