R-根据前一行中的值为数据帧中的行创建唯一的序列ID

时间:2019-05-24 16:40:16

标签: r

我正在使用一个旅行数据集,该数据集提供每个人旅行的不连续部分的信息,包括该部分的距离和目的(例如上班,购物,回家)。它被组织在一个数据框中。我想将这些段分组为我所说的“链接”或“循环”行程,每当前面的段中有回程时增加链/回路的数量。

在r中,我试图构造一个包含ifelse的for循环,该循环引用来自先前迭代的变量值,然后填充一个我已经用空值创建的新列。 (我知道这听起来有点钝)。基本上,我试图做出与在Excel中构造一系列嵌套if的Excel类似的工作。 (= IF(DF2 = DF1,IF(DG1 = 11,DI1 + 1,DI1),1)。这是第三行的公式,它引用的是紧接在前一行的值。

这是数据的dput代码输出:

structure(list(h_id = c(1000002L, 1000002L, 1000002L, 1000002L, 
1000013L, 1000013L, 1000013L, 1000013L, 1000013L, 1000013L, 1000013L, 1000013L), p_ID = c(10000022L, 10000022L, 10000022L, 
10000022L, 10000131L, 10000131L, 10000132L,10000132L, 10000132L,10000132L,10000132L,10000132L), t_pur = c(6L, 11L, 7L, 11L, 
5L, 11L, 1L, 2L, 2L, 11L, 6L, 11L), t_distance = c(753.154936, 753.154936, 4681.630497, 
4681.630497, 616.0517311, 616.0517311, 9626,7984, 641.3675, 15076.6182, 21407.5585, 24273.3116, 24273.3116), X = c(1L, 1L, 2L, 2L, 
1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L), Conc = c("10000022-1", "10000022-1", "10000022-2", "10000022-2", 
"10000131-1", "10000131-1", "10000132-1", "10000132-1", "10000132-1", "10000132-1", "10000132-2", "10000132-2" ), t_mode1 = c(1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 
1L), has_work = c(0, 0, 0, 0, 0, 0,1, 0, 0, 0, 0, 0), newcol = c(1, 1, 1, 1, 1, 
1, 1, 1, 1, 1,1, 1)), .Names = c("h_id", "p_ID", "t_pur", "t_distance", "X", "Conc", 
"t_mode1", "has_work", "newcol"), row.names = 3:14, class = "data.frame")
for (i in 1:nrow(loops4)) {
  ifelse(i == 1, loops4$newcol[i] <- 1,
         ifelse(loops4$p_ID[i-1]==loops4$p_ID,
                ifelse(loops4$t_pur[i-1]==11,
                       loops4$newcol[i] <- loops4$newcol[i-1]+1, 
                       loops4$newcol[i-1]), loops4$newcol[i] <- 1)) 
}

在这里,loops4是我的数据帧。我创建了newcol来保存循环标识符。 p_ID是与每个人相关联的唯一标识符,t_pur是行程段的目的,“ 11”是与“回家”目的相对应的值。 (我想在前面的段每次返回时都启动一个新的循环标识符)。之后,我可以将唯一的人员ID和循环ID串联起来,为每个循环创建唯一的标识符。第一个ifelse只是为第一条记录分配一个1到循环标识符,因为该循环没有先前的值可以查询

我希望循环遍历数据帧的每一行,首先检查记录是否与上一条记录中提到的人相同。如果是这样,则应检查上一行的行程目的是否为“ 11”。如果是这样,则应在前面的标识符上加1以表示新的循环。如果它的跳闸目的不是“ 11”,则它应分配与上一行完全相同的循环标识符,然后移至下一行。它运行时,首先,似乎要花费大量时间,其次,它用1填充所有内容,而不是按照我的预期进行递增和重新启动。

我期望这样的数据框。 X是从Excel正确计算得出的值。 newcol是我试图在newcol中计算r中的值的列。 newcol值应与X相同,但不相同。 (我更新了下表以在newcol中反映我希望在输出中看到的内容)。

   h_id     p_ID t_pur t_distance X       Conc t_mode1 has_work newcol
1000002 10000022     6      753.2 1 10000022-1       1        0      1
1000002 10000022    11      753.2 1 10000022-1       1        0      1
1000002 10000022     7     4681.6 2 10000022-2       1        0      2
1000002 10000022    11     4681.6 2 10000022-2       1        0      2
1000013 10000131     5      616.1 1 10000131-1       1        0      1
1000013 10000131    11      616.1 1 10000131-1       1        0      1
1000013 10000132     1     9626.8 1 10000132-1       1        1      1
1000013 10000132     2      641.4 1 10000132-1       1        0      1
1000013 10000132     2    15076.6 1 10000132-1       1        0      1
1000013 10000132    11    21407.6 1 10000132-1       1        0      1
1000013 10000132     6    24273.3 2 10000132-2       1        0      2
1000013 10000132    11    24273.3 2 10000132-2       1        0      2

更新:

我回过头来,根据下面的评论对ifelse构造中的赋值进行了一些思考,意识到这没有多大意义。所以我尝试重写代码,如下所示:

for (i in 1:nrow(loops4)) {
  loops4$newcol[i] <- ifelse(i == 1, 1, ifelse (loops4$p_ID[i-1]==loops4$p_ID[i], ifelse(loops4$t_pur[i-1]==11, loops4$newcol[i-1]+1, loops$newcol[i-1], 1)))
}

但是我得到了同样的意外结果。

更新后的更新:

以前的Dput数据中可能存在错误。我手动添加了一些值。我在下面粘贴了新的dput数据。

structure(list(h_id = c(1000002L, 1000002L, 1000002L, 1000002L, 
1000013L, 1000013L, 1000013L, 1000013L, 1000013L, 1000013L, 1000013L, 
1000013L), p_ID = c(10000022L, 10000022L, 10000022L, 10000022L, 
10000131L, 10000131L, 10000132L, 10000132L, 10000132L, 10000132L, 
10000132L, 10000132L), t_pur = c(6L, 11L, 7L, 11L, 5L, 11L, 1L, 
2L, 2L, 11L, 6L, 11L), t_distance = c(753.154936, 753.154936, 
4681.630497, 4681.630497, 616.0517311, 616.0517311, 9626.798385, 
641.3674532, 15076.61817, 21407.55851, 24273.31161, 24273.31161
), X = c(1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L), Conc = c("10000022-1", 
"10000022-1", "10000022-2", "10000022-2", "10000131-1", "10000131-1", 
"10000132-1", "10000132-1", "10000132-1", "10000132-1", "10000132-2", 
"10000132-2"), t_mode1 = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L), has_work = c(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0), 
    newcol = c(1L, 1L, 2L, 2L, 1L, 1L, 0L, 0L, 1L, 1L, 2L, 2L
    )), .Names = c("h_id", "p_ID", "t_pur", "t_distance", "X", 
"Conc", "t_mode1", "has_work", "newcol"), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -12L))

并且我尝试了以下有用的dplyr方法。

loops_good <- loops5 %>%
  group_by(h_id) %>% group_by (p_ID) %>%
  mutate(newcol = cumsum(lead(t_pur, default = 0) == 11)) %>%
  ungroup()

我得到的结果几乎是我一直期望的结果。但不完全是。第7行到第10行应在newcol中与相同的标识符一起分组,因为没有中间的“ 11”。 t_pur序列为1、2、2、11。但是在下面的输出中,newcol值分别为0、0、1、1。

基本上,我正在尝试将各个部分链接成整体行程,从每次有t_pur ==“ 11”表示的返程回家开始。有时,它只是一个往返(两个部分)。但有时,如第7-10行,它是4个细分。

实际输出:

      h_id     p_ID t_pur t_distance     X Conc       t_mode1 has_work newcol
     <int>    <int> <int>      <dbl> <int> <chr>        <int>    <dbl>  <int>
 1 1000002 10000022     6       753.     1 10000022-1       1        0      1
 2 1000002 10000022    11       753.     1 10000022-1       1        0      1
 3 1000002 10000022     7      4682.     2 10000022-2       1        0      2
 4 1000002 10000022    11      4682.     2 10000022-2       1        0      2
 5 1000013 10000131     5       616.     1 10000131-1       1        0      1
 6 1000013 10000131    11       616.     1 10000131-1       1        0      1
 7 1000013 10000132     1      9627.     1 10000132-1       1        1      0
 8 1000013 10000132     2       641.     1 10000132-1       1        0      0
 9 1000013 10000132     2     15077.     1 10000132-1       1        0      1
10 1000013 10000132    11     21408.     1 10000132-1       1        0      1
11 1000013 10000132     6     24273.     2 10000132-2       1        0      2
12 1000013 10000132    11     24273.     2 10000132-2       1        0      2

希望输出:

      h_id     p_ID t_pur t_distance     X Conc       t_mode1 has_work newcol
     <int>    <int> <int>      <dbl> <int> <chr>        <int>    <dbl>  <int>
 1 1000002 10000022     6       753.     1 10000022-1       1        0      1
 2 1000002 10000022    11       753.     1 10000022-1       1        0      1
 3 1000002 10000022     7      4682.     2 10000022-2       1        0      2
 4 1000002 10000022    11      4682.     2 10000022-2       1        0      2
 5 1000013 10000131     5       616.     1 10000131-1       1        0      1
 6 1000013 10000131    11       616.     1 10000131-1       1        0      1
 7 1000013 10000132     1      9627.     1 10000132-1       1        1      1
 8 1000013 10000132     2       641.     1 10000132-1       1        0      1
 9 1000013 10000132     2     15077.     1 10000132-1       1        0      1
10 1000013 10000132    11     21408.     1 10000132-1       1        0      1
11 1000013 10000132     6     24273.     2 10000132-2       1        0      2
12 1000013 10000132    11     24273.     2 10000132-2       1        0      2

1 个答案:

答案 0 :(得分:0)

我想我知道你想要的是什么...

说明:

  • 当您说出“首先检查记录是否指向同一个人” 时,表明您应该按照变量ergo dplyr::group_bydata.table分组by=和基数R的by()
  • 使用简单的leadshift,我们包含 next 行的值的逻辑,以便将其分配给 this 行; b / c这两个函数都不知道在查看特定人的最后一行时该怎么做,我们必须使用default=fill=提供默认值,或者使用{{1 }}

已编辑以获取最新的逻辑和理解。


c(...[-1], 0)

dplyr

library(dplyr) x %>% group_by(p_ID) %>% mutate(newcol = cumsum(lag(t_pur == 11, default = TRUE))) %>% ungroup() # # A tibble: 12 x 9 # h_id p_ID t_pur t_distance X Conc t_mode1 has_work newcol # <int> <int> <int> <dbl> <int> <chr> <int> <dbl> <int> # 1 1000002 10000022 6 753. 1 10000022-1 1 0 1 # 2 1000002 10000022 11 753. 1 10000022-1 1 0 1 # 3 1000002 10000022 7 4682. 2 10000022-2 1 0 2 # 4 1000002 10000022 11 4682. 2 10000022-2 1 0 2 # 5 1000013 10000131 5 616. 1 10000131-1 1 0 1 # 6 1000013 10000131 11 616. 1 10000131-1 1 0 1 # 7 1000013 10000132 1 9627. 1 10000132-1 1 1 1 # 8 1000013 10000132 2 641. 1 10000132-1 1 0 1 # 9 1000013 10000132 2 15077. 1 10000132-1 1 0 1 # 10 1000013 10000132 11 21408. 1 10000132-1 1 0 1 # 11 1000013 10000132 6 24273. 2 10000132-2 1 0 2 # 12 1000013 10000132 11 24273. 2 10000132-2 1 0 2

data.table

基本R

library(data.table)
xDT <- x
xDT$newcol <- NULL
setDT(xDT)
xDT[, newcol := cumsum(shift(t_pur == 11, type = "lag", fill = TRUE)), by = "p_ID"]