2015-02-10 48 views
5

Tôi có một khung dữ liệu mà trông như sau:nhóm, so sánh, và đếm hàng trong r

 system Id initial final 
665  9 16001 6070 6071 
683  10 16001 6100 6101 
696  11 16001 6101 6113 
712  10 16971 6150 6151 
715  11 16971 6151 6163 
4966  7 4118 10238 10242 
5031  9 4118 10260 10278 
5088  10 4118 10279 10304 
5115  11 4118 10305 10317 


structure(list(system = c(9L, 10L, 11L, 10L, 11L, 7L, 9L, 10L, 
11L), Id = c(16001L, 16001L, 16001L, 16971L, 16971L, 4118L, 4118L, 
4118L, 4118L), initial = c(6070, 6100, 6101, 6150, 6151, 10238, 
10260, 10279, 10305), final = c(6071, 6101, 6113, 6151, 6163, 
10242, 10278, 10304, 10317)), .Names = c("system", "Id", "initial", 
"final"), row.names = c(665L, 683L, 696L, 712L, 715L, 4966L, 
5031L, 5088L, 5115L), class = "data.frame") 

Tôi muốn để có được một khung dữ liệu mới với cấu trúc tiếp theo

 Id system length initial final 
1 16001 9,10,11  3 6070 6113 
2 16971 10,11  2 6150 6163 
3 4118  7  1 10238 10242 
4 4118 9,10,11  3 10260 10317 


structure(list(Id = c(16001L, 16971L, 4118L, 4118L), system =  structure(c(3L, 
1L, 2L, 3L), .Label = c("10,11", "7", "9,10,11"), class =  "factor"), 
    length = c(3L, 2L, 1L, 3L), initial = c(6070L, 6150L, 10238L, 
    10260L), final = c(6113, 6163, 10242, 10317)), .Names = c("Id", 
"system", "length", "initial", "final"), class = "data.frame",  row.names = c(NA, 
-4L)) 

Nhóm là bởi Id và sự khác biệt (giữa các hàng) trong trường "hệ thống" bằng một. Ngoài ra tôi muốn có được "hệ thống" khác nhau và bao nhiêu trong số đó liên quan đến nhóm. Cuối cùng một cột với "đầu tiên" đầu tiên và cuối cùng "cuối cùng" cũng tham gia.

Có thể thực hiện điều đó trong r? Cảm ơn.

Trả lời

3

Bạn có thể sử dụng data.table. Chuyển đổi "data.frame" thành "data.table" (setDT), tạo biến nhóm "indx" bằng cách lấy sự khác biệt của các phần tử liền kề của "hệ thống" (diff(system)), cumsum vectơ logic, sử dụng "Id" và "indx "làm biến nhóm để lấy thống kê.

library(data.table) 
setDT(df)[,list(system=toString(system), length=.N, initial=initial[1L], 
    final=final[.N]), by=list(Id,indx=cumsum(c(TRUE, diff(system)!=1)))][, 
    indx:=NULL][] 

#  Id system length initial final 
#1: 16001 9, 10, 11  3 6070 6113 
#2: 16971 10, 11  2 6150 6163 
#3: 4118   7  1 10238 10242 
#4: 4118 9, 10, 11  3 10260 10317 

Hoặc dựa trên bình luận @ jazzurro về việc sử dụng first/last chức năng từ dplyr,

library(dplyr) 
df %>% 
    group_by(indx=cumsum(c(TRUE, diff(system)!=1)), Id) %>% 
    summarise(system=toString(system), length=n(), 
    initial=first(initial), final=last(final)) 
+1

có thể sử dụng 'đầu tiên()' và ' last() 'là một tùy chọn khác ở đây? 'first()' là từ dplyr. – jazzurro

+0

@jazzurro Tôi nghĩ nó hoạt động. Bạn có thể đăng bài đó như là một giải pháp dplyr. – akrun

+0

Tôi vẫn tự hỏi nếu nó là một điều tốt để sử dụng một số chức năng từ 'dplyr' trong' data.table'. Giải pháp 'dplyr' sẽ chỉ là bản dịch mã của bạn. Nếu bạn vui lòng viết một cái, xin hãy tiếp tục. Tôi sẽ để nó cho bạn. :) – jazzurro

1

Một giải pháp mà không data.table, nhưng plyr:

library(plyr) 

func = function(subdf) 
{ 
    bool = c(diff(subdf$system),1)==1 
    ldply(split(subdf, bool), function(u){ 
     data.frame(system = paste(u$system, collapse=','), 
        Id  = unique(u$Id), 
        length = nrow(u), 
        initial= head(u,1)$initial, 
        final = tail(u,1)$final) 
    }) 
} 


ldply(split(df, df$Id), func) 

# .id system length Id initial final 
#1 FALSE  7  1 4118 10238 10242 
#2 TRUE 9,10,11  3 4118 10260 10317 
#3 TRUE 9,10,11  3 16001 6070 6113 
#4 TRUE 10,11  2 16971 6150 6163