编辑:下面的答案解决了我的第一个问题,但是我没有提到列表也包括单个船只,因此需要考虑它们。
我有一个船只清单,我想根据某些条件创建路线。我已经产生了以下列表,并且我想为每艘船的每个航路段创建一个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,但未考虑新船。轨道在港口或航行中开始是随机的,日期也是随机的。
答案 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::rleid
和dplyr
的解决方案。这使用游程长度编码首先基于Sailing.Port
(ID1
)创建分组变量。对于每个组,如果它是“ 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))