2016-06-06 35 views
4

我已經搜索過SO,以便實現我所需要的運行方式,所以它就這樣走了。 後來我發現了包dplyr及其潛力。我在想這個軟件包可以做我想做的,我只是不知道如何。這是我的數據的一小部分,但應該代表我的問題。dplyr mutate函數垂直地評估列(當前,上一個,下一個)內的值

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和站列來評估時間列內的行。具體來說,我希望函數(dplyr?)能夠評估每個時間行,並將時間與前一時間(第一行)和第二行(第一行)進行比較。如果當前行的時間在上一行和/或下一行的1小時內,並且當前行的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 
+1

我不認爲你需要dplyr,我想你只需要一對夫婦'diff'操作。請注意,「類」POSIXct「表示自1970年開始(在UTC時區)以秒爲單位的(有符號)秒數」。所以你會希望查找小於3600秒的差異。 – C8H10N4O2

+0

不確定'dplyr',但data.table有滾動連接,似乎以最有效的方式解決您的問題。最近的一篇文章詳細描述了該功能:[瞭解data.table滾動聯接](http://r-norberg.blogspot.co.uk/2016/06/understanding-datatable-rolling-joins.html)。提供一個小時即可使用60 * 60(因爲POSIXct是秒數)。這樣你就可以使用二進制合併來檢測這些行。如果純粹的表現不是你的目標,那麼'shift(x)'或'c(NA,x [ - 。N])'/'c(x [-1L],NA)'應該足以創建列來比較。 – jangorecki

回答

5

下面是使用difftimedplyr發生變異功能的選項。首先,我們使用group_by操作來確保比較在ID和站的每個唯一組合內。 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 
+0

這確實是我正在尋找的。你能詳細解釋一下嗎?謝謝。 – FlyingDutch

+0

剛剛更新了答案。 – Psidom

+0

太棒了,非常感謝 – FlyingDutch

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 
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 
+1

加上一個工作(不漂亮) – C8H10N4O2