2017-09-27 51 views
3

我有一個樣本數據集,用於跟蹤不同車站的自行車軌跡。我的目標是找到間隔的自行車保持在與difftime()特定站,在這種情況下,站B.引用前導行中的數據

> test 
    bikeid start_station   starttime end_station    endtime 
1  1    A 2017-09-25 01:00:00   B 2017-09-25 01:30:00 
2  1    B 2017-09-25 07:30:00   C 2017-09-25 08:00:00 
3  1    C 2017-09-25 10:00:00   A 2017-09-25 10:30:00 
4  1    A 2017-09-25 13:00:00   C 2017-09-25 13:30:00 
5  1    C 2017-09-25 15:30:00   B 2017-09-25 16:00:00 
6  1    B 2017-09-25 18:00:00   B 2017-09-25 18:30:00 
7  1    B 2017-09-25 19:00:00   A 2017-09-25 19:30:00 
8  1    А 2017-09-25 20:00:00   B 2017-09-25 20:30:00 
9  1    C 2017-09-25 22:00:00   C 2017-09-25 22:30:00 
10  1    B 2017-09-25 23:00:00   C 2017-09-25 23:30:00 

有時,自行車不要在他們結束了同一個站開始,這些案件應該被忽略。在上述數據集中,我們可以看到在01:30:0007:30:00之間經過360分鐘,在16:00:0018:00:00之間經過120分鐘,並且在18:30:0019:00:00之間經過了30分鐘。第8行和第10行被忽略,因爲自行車不是在它結束的同一個車站開始的。因此,輸出矢量應爲:

[1] 360 120 30 

下面的代碼使用的是不產生所需的輸出:

sapply(test$starttime[test$end_station == "B"], function(x, et) difftime(et[x < et][1], x, units = "mins"), et = test$endtime[test$start_station == "B"]) 

一個如何將考慮到下一行並計算difftime()只有當end_stationstart_station在下面一行是否相等?在dplyr中使用lead()?任何建議,將不勝感激

這裏是樣本數據:

> dput(test) 
structure(list(bikeid = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1), start_station = c("A", 
"B", "C", "A", "C", "B", "B", "А", "C", "B"), starttime = structure(c(1506315600, 
1506339000, 1506348000, 1506358800, 1506367800, 1506376800, 1506380400, 
1506384000, 1506391200, 1506394800), class = c("POSIXct", "POSIXt" 
), tzone = ""), end_station = c("B", "C", "A", "C", "B", "B", 
"A", "B", "C", "C"), endtime = structure(c(1506317400, 1506340800, 
1506349800, 1506360600, 1506369600, 1506378600, 1506382200, 1506385800, 
1506393000, 1506396600), class = c("POSIXct", "POSIXt"), tzone = "")), .Names = c("bikeid", 
"start_station", "starttime", "end_station", "endtime"), row.names = c(NA, 
-10L), class = "data.frame") 

回答

5

重塑as suggested最後一次......

library(data.table) 

mtest = melt(setDT(test), id="bikeid", 
    meas = patterns("_station", "time"), 
    variable.name = "event", 
    value.name = c("station", "time")) 
mtest[.(factor(1:2), c("start", "end")), on=.(event), event := i.V2] 
setkey(mtest, bikeid, time) 

然後回到寬的法術,而自行車是空閒.. 。

idleDT = dcast(mtest[-c(1,.N)][, g := rep(1:.N, each=2, length.out=.N)], 
    g ~ rowid(g), value.var=c("station", "time")) 

    g station_1 station_2    time_1    time_2 
1: 1   B   B 2017-09-25 01:30:00 2017-09-25 07:30:00 
2: 2   C   C 2017-09-25 08:00:00 2017-09-25 10:00:00 
3: 3   A   A 2017-09-25 10:30:00 2017-09-25 13:00:00 
4: 4   C   C 2017-09-25 13:30:00 2017-09-25 15:30:00 
5: 5   B   B 2017-09-25 16:00:00 2017-09-25 18:00:00 
6: 6   B   B 2017-09-25 18:30:00 2017-09-25 19:00:00 
7: 7   A <U+0410> 2017-09-25 19:30:00 2017-09-25 20:00:00 
8: 8   B   C 2017-09-25 20:30:00 2017-09-25 22:00:00 
9: 9   C   B 2017-09-25 22:30:00 2017-09-25 23:00:00 

然後加入或過濾並計算...

idleDT[.("B", "B"), on=.(station_1, station_2), time_2 - time_1 ] 

Time differences in mins 
[1] 360 120 30 

評論

也許我應該解釋一下爲什麼我喜歡長格式mtest在OP的test,即使我直接回到寬幅的分析(感謝@Henrik)...

  • 工作站可能/應該可以成爲一個因素,如果你把它分成兩列在覈心數據中,確保這兩個因素具有相同的水平是一個負擔。
  • 這些數據大概是按照事件記錄的(比如「自行車左」和「自行車到達」),而不是以旅行方式記錄。例如,如果有人偷了自行車或丟失了自行車,例如,endtimeend_station應該在邏輯上丟失,但在我看來這更容易以長格式記錄。
  • 根據我的經驗,測量數據甚至可以連續有兩個「自行車到達」事件,儘管它在邏輯上不合理,但任何可能出錯的數據都會出錯。如果發生這種情況,你很難弄清楚如何在旅行方面以廣泛的格式記錄它。

一般來說,我只是將我的tidy data(也許過分熱心的或錯誤)的理解,有關數據佈局的鏈接哈德利的投訴riffing其中「[C] olumn頭是值,而不是變量名。」

+0

我敢肯定,100%你有一個很好的理由使用'melt'&'dcast'打造 「idleDT」 ,而不是類似'test [,'':=''(prev_endstation = shift(end_station),prev_endtime = shift(endtime))]'',但不幸的是,我目前的大腦狀態不允許我發現它。抱歉。 Plz發送解釋。 ;) – Henrik

+1

@Henrik我編輯了一個冗長的解釋,我同意需要一些解釋。希望它是有道理的,但我不確定它是否會讓每個人都信服。謝謝 :) – Frank

1

一個dplyr解決方案:

library(dplyr) 
df %>% 
    mutate(lag_end_station = lag(end_station), 
     lag_end_time = lag(endtime)) %>% 
    filter(start_station == "B" & lag_end_station == "B") %>% 
    transmute(interval = difftime(starttime, lag_end_time)) 

結果:

interval 
1 360 mins 
2 120 mins 
3 30 mins