如何根据上一行中的值进行分组?

时间:2018-09-27 14:24:20

标签: r group-by

编辑:下面的答案解决了我的第一个问题,但是我没有提到列表也包括单个船只,因此需要考虑它们。

我有一个船只清单,我想根据某些条件创建路线。我已经产生了以下列表,并且我想为每艘船的每个航路段创建一个TRACKID。

VESSEL  Date    Sailing/Port
1      01.02.2016   SAILING
1      02.02.2016   SAILING
1      03.02.2016   SAILING
1      04.02.2016   SAILING
1      05.02.2016   SAILING
1      06.02.2016   PORT
1      07.02.2016   PORT
1      08.02.2016   PORT
1      09.02.2016   PORT
1      10.02.2016   SAILING
2      11.02.2016   SAILING
2      12.02.2016   SAILING
2      13.02.2016   SAILING
2      14.02.2016   PORT
2      15.02.2016   PORT
2      16.02.2016   SAILING

如果该船正在航行,我希望它保持相同的TRACKID,直到它进入港口为止。应将PORT中前半部分的位置分配给与进入端口之前相同的TRACKID。应该给后半部分一个新的TRACKID,该ID一直保留到下一个端口。当引入新船时,我还需要更改TRACKID。

VESSEL      Date      Sailing/Port  TRACKID     
   1      01.02.2016    SAILING     1
   1      02.02.2016    SAILING     1
   1      03.02.2016    SAILING     1
   1      04.02.2016    SAILING     1
   1      05.02.2016    SAILING     1
   1      06.02.2016    PORT        1
   1      07.02.2016    PORT        1
   1      08.02.2016    PORT        2
   1      09.02.2016    PORT        2
   1      10.02.2016    SAILING     2
   2      11.02.2016    SAILING     3
   2      12.02.2016    SAILING     3
   2      13.02.2016    SAILING     3
   2      14.02.2016    PORT        3
   2      15.02.2016    PORT        4
   2      16.02.2016    SAILING     4

以下答案能够使用航行/港口创建TRACKID,但未考虑新船。轨道在港口或航行中开始是随机的,日期也是随机的。

3 个答案:

答案 0 :(得分:1)

这是不使用for并使用tidyverse和zoo软件包(对于na.locf)的解决方案。它为SAILING或PORT的每个连续序列创建一个不同的序列号“ a”,然后将每个(“ PORT”,a)组的开始和结尾分别更改为上一个或下一个SAILING组。

group_number <- (function(){i = 0L; function() i <<- i+1L })()

df %>% 
  mutate(id=row_number(),
         a=ifelse(is.na(lag(Sailing.Port))|(lag(Sailing.Port)!=Sailing.Port),id,NA)) %>%
  mutate(a=na.locf(a)) %>%         # propagate the id of the 1st row of sequence
  group_by(a) %>%
  mutate(g=group_number()) %>%
  mutate(g=ifelse(Sailing.Port=="PORT",ifelse(row_number()<=(n()/2),g-1,g+1),g)) %>%
  ungroup %>% select(-a,-id)
## A tibble: 16 x 3
#   Date       Sailing.Port     g
#   <fct>      <fct>        <dbl>
# 1 01.02.2016 SAILING          1
# 2 02.02.2016 SAILING          1
# 3 03.02.2016 SAILING          1
# 4 04.02.2016 SAILING          1
# 5 05.02.2016 SAILING          1
# 6 06.02.2016 PORT             1
# 7 07.02.2016 PORT             1
# 8 08.02.2016 PORT             3
# 9 09.02.2016 PORT             3
#10 10.02.2016 SAILING          3
#11 11.02.2016 SAILING          3
#12 12.02.2016 SAILING          3
#13 13.02.2016 SAILING          3
#14 14.02.2016 PORT             3
#15 15.02.2016 PORT             5
#16 16.02.2016 SAILING          5

答案 1 :(得分:0)

我要遍历一个新的向量。像这样的东西。

temp.id<-1
for(n in 2:N){
 if(status[n]=="port" & status[n-1]=="sailing"){
  temp.id<-temp.id+1
 }
 leg[n]<-temp.id
}

那只能让您进入港口的第一天。要找到中点,您将需要在其中进行第二次循环。像这样的东西。

temp.days<-0
for(m in (n+1):N){
 temp.days<-temp.days+1
 if(status[m]=="sailing"){break}
}

然后,您需要做一些算术运算,并弄清楚如何处理奇数天。

答案 2 :(得分:0)

这是使用data.table::rleiddplyr的解决方案。这使用游程长度编码首先基于Sailing.PortID1)创建分组变量。对于每个组,如果它是“ PORT”的后半部分,则将其设置为1,否则将其设置为0(ID2)。使用该指示符,将ID1替换为另一个rle分组变量,并使用TRACKID生成cumsum

library(dplyr)
library(data.table)

df %>%
  group_by(ID1 = rleid(Sailing.Port)) %>%
  mutate(ID2 = if_else((row_number() > n()/2) & Sailing.Port == "PORT", 1, 0))  %>%
  ungroup() %>%
  group_by(ID1 = rleid(ID2)) %>%
  mutate(ID3 = if_else(ID2 == 1 & row_number() == 1, 1, 0)) %>%
  ungroup() %>%
  mutate(TRACKID = cumsum(ID3)+1) %>%
  select(-ID1, -ID2, -ID3)

输出:

# A tibble: 16 x 3
   Date       Sailing.Port TRACKID
   <fct>      <fct>          <dbl>
 1 01.02.2016 SAILING            1
 2 02.02.2016 SAILING            1
 3 03.02.2016 SAILING            1
 4 04.02.2016 SAILING            1
 5 05.02.2016 SAILING            1
 6 06.02.2016 PORT               1
 7 07.02.2016 PORT               1
 8 08.02.2016 PORT               2
 9 09.02.2016 PORT               2
10 10.02.2016 SAILING            2
11 11.02.2016 SAILING            2
12 12.02.2016 SAILING            2
13 13.02.2016 SAILING            2
14 14.02.2016 PORT               2
15 15.02.2016 PORT               3
16 16.02.2016 SAILING            3

数据:

df <- structure(list(Date = structure(1:16, .Label = c("01.02.2016", 
"02.02.2016", "03.02.2016", "04.02.2016", "05.02.2016", "06.02.2016", 
"07.02.2016", "08.02.2016", "09.02.2016", "10.02.2016", "11.02.2016", 
"12.02.2016", "13.02.2016", "14.02.2016", "15.02.2016", "16.02.2016"
), class = "factor"), Sailing.Port = structure(c(2L, 2L, 2L, 
2L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 1L, 2L), .Label = c("PORT", 
"SAILING"), class = "factor")), .Names = c("Date", "Sailing.Port"
), class = "data.frame", row.names = c(NA, -16L))