为每个组ID

时间:2016-12-27 19:18:12

标签: r

我已经广泛研究了堆栈溢出的解决方案,但还没有找到适合我的解决方案。 我的数据框看起来像这样:

id    time    latitude    longitude
A     11:10   381746.0    6008345
A     11:11   381726.2    6008294
B     10:56   381703.0    6008214
B     10:57   381679.7    6008134
C     4:30    381654.4    6008083
C     4:31    381629.2    6008033

我想在每个id的END处插入一个新行。在这一行中,我希望'id'和'time'与之前的观察相同。我希望纬度和经度为'394681.4'和'6017550'(对应于所有id的结束位置)。

id    time    latitude    longitude
A     11:10   381746.0    6008345
A     11:11   381726.2    6008294
A     11:11   394681.4    6017550
B     10:56   381703.0    6008214
B     10:57   381679.7    6008134
B     10:57   394681.4    6017550
C     4:30    381654.4    6008083
C     4:31    381629.2    6008033
C     4:32    394681.4    6017550

有人能想到解决方案吗? Dplyr或数据表解决方案首选。

4 个答案:

答案 0 :(得分:10)

我们可以使用data.table执行此操作。将'data.frame'转换为'data.table'(setDT(df1)),按'id'分组,使用tail获取最后一行,使用new分配'latitude'和'longitude'值{,rbind包含原始数据集,order包含'id'。

library(data.table)
rbind(setDT(df1), df1[, tail(.SD, 1) , by = id
        ][, c("latitude", "longitude") := .(394681.4,  6017550)
         ])[order(id)]
#    id  time latitude longitude
#1:  A 11:10 381746.0   6008345
#2:  A 11:11 381726.2   6008294
#3:  A 11:11 394681.4   6017550
#4:  B 10:56 381703.0   6008214
#5:  B 10:57 381679.7   6008134
#6:  B 10:57 394681.4   6017550
#7:  C  4:30 381654.4   6008083
#8:  C  4:31 381629.2   6008033
#9:  C  4:31 394681.4   6017550

或使用dplyr,使用类似的方法

library(dplyr)
df1 %>%
   group_by(id) %>%
   summarise(time = last(time)) %>%
   mutate(latitude = 394681.4, longitude = 6017550) %>% 
   bind_rows(df1, .) %>% 
   arrange(id)

答案 1 :(得分:2)

使用split-apply-combine概念的基础R解决方案。

do.call(rbind, lapply(split(df, df$id), 
                      function(x) rbind(x,
                         within(x[nrow(x),], {latitude <- 394681.4; longitude <- 6017550}))))

返回

     id  time latitude longitude
A.1   A 11:10 381746.0   6008345
A.2   A 11:11 381726.2   6008294
A.21  A 11:11 394681.4   6017550
B.3   B 10:56 381703.0   6008214
B.4   B 10:57 381679.7   6008134
B.41  B 10:57 394681.4   6017550
C.5   C  4:30 381654.4   6008083
C.6   C  4:31 381629.2   6008033
C.61  C  4:31 394681.4   6017550

split将data.frame分解为data.frames列表,lapply rbind是每个data.frame的最后一行,do.call {{1}结果的data.frames列表。每个data.frame的最后一行是使用rbind生成的,它返回给定的data.frame的修改版本。 within用于选择最后一行。引用@ akrun的回答,nrow可以替换为x[nrow(x),]

答案 2 :(得分:1)

使用dplyr

   library(dplyr)

 # data:   
    df <- structure(list(id = structure(c(1L, 1L, 2L, 2L, 3L, 3L), .Label = c("A", 
    "B", "C"), class = "factor"), time = structure(c(3L, 4L, 1L, 
    2L, 5L, 6L), .Label = c("10:56", "10:57", "11:10", "11:11", "4:30", 
    "4:31"), class = "factor"), latitude = c(381746, 381726.2, 381703, 
    381679.7, 381654.4, 381629.2), longitude = c(6008345L, 6008294L, 
    6008214L, 6008134L, 6008083L, 6008033L)), .Names = c("id", "time", 
    "latitude", "longitude"), row.names = c(NA, -6L), class = c("tbl_df", 
    "tbl", "data.frame"))

 # code: 

    df %>% group_by(id) %>% 
        do({ df <- . 
             last_row           <- df %>% slice(n())
             last_row$latitude  <- 394681.4
             last_row$longitude <- 6017550
             df                 <- bind_rows(df, last_row)
        })

答案 3 :(得分:0)

dplyr 方法

df1 %>%
   group_by(id) %>%
   slice_tail() %>%
   bind_rows(df1) %>% 
   arrange(id,time)