2014-10-10 15 views
5

Tôi muốn tính số lượng mặt hàng theo thời gian sử dụng ngày Bắt đầu và Ngày kết thúc của chúng.R- Tính số lượng mặt hàng theo thời gian sử dụng ngày bắt đầu và ngày kết thúc

Một số dữ liệu mẫu

START <- as.Date(c("2014-01-01", "2014-01-02","2014-01-03","2014-01-03")) 
END <- as.Date(c("2014-01-04", "2014-01-03","2014-01-03","2014-01-04")) 
df <- data.frame(START,END) 
df 

cho

 START  END 
1 2014-01-01 2014-01-04 
2 2014-01-02 2014-01-03 
3 2014-01-03 2014-01-03 
4 2014-01-03 2014-01-04 

Một bảng hiển thị một số các mặt hàng này theo thời gian (dựa trên Start và End của họ lần) như sau:

DATETIME COUNT 
2014-01-01 1 
2014-01-02 2 
2014-01-03 4 
2014-01-04 2 

Điều này có thể được thực hiện bằng cách sử dụng R, đặc biệt là sử dụng dplyr? Cảm ơn nhiều.

+0

@RichardScriven. Mỗi hàng xác định một khoảng thời gian từ START đến END. Ví dụ '2014-01-03' là một phần của tất cả bốn giai đoạn được hiển thị ở đây. – flodel

Trả lời

6

Điều này sẽ thực hiện. Bạn có thể thay đổi tên cột nếu cần.

as.data.frame(table(Reduce(c, Map(seq, df$START, df$END, by = 1)))) 
#   Var1 Freq 
# 1 2014-01-01 1 
# 2 2014-01-02 2 
# 3 2014-01-03 4 
# 4 2014-01-04 2 

Như đã đề cập trong các ý kiến, Var1 trong giải pháp trên tại là một yếu tố, và không phải là một ngày. Để giữ cho lớp ngày trong cột đầu tiên, bạn có thể làm một số công việc nhiều hơn với các giải pháp trên, hoặc sử dụng plyr::count thay vì as.data.frame(table(...))

library(plyr) 
count(Reduce(c, Map(seq, df$START, df$END, by = 1))) 
#   x freq 
# 1 2014-01-01 1 
# 2 2014-01-02 2 
# 3 2014-01-03 4 
# 4 2014-01-04 2 
+0

Lưu ý rằng nó vẫn hoạt động nếu 'Reduce' được thay thế bằng' do.call'. –

+0

Hãy coi chừng rằng 'Var1' bây giờ là một yếu tố, không phải là một ngày tháng. – hadley

2

Bạn có thể sử dụng data.table

library(data.table) 
DT <- setDT(df)[, list(DATETIME= seq(START, END, by=1)), by=1:nrow(df)][, 
          list(COUNT=.N), by=DATETIME] 
DT 
#  DATETIME COUNT 
#1: 2014-01-01  1 
#2: 2014-01-02  2 
#3: 2014-01-03  4 
#4: 2014-01-04  2 

Từ phiên bản 1.9.4+, bạn cũng có thể sử dụng hàm foverlaps() để thực hiện "chồng chéo tham gia". Nó hiệu quả hơn vì nó không phải mở rộng ngày cho mỗi hàng đầu tiên, và sau đó đếm. Đây là cách:

require(data.table) ## 1.9.4 
setDT(df) ## convert your data.frame to data.table by reference 

## 1. Some preprocessing: 
# create a lookup - the dates for which you need the count, and set key 
dates = seq(as.Date("2014-01-01"), as.Date("2014-01-04"), by="days") 
lookup = data.table(START=dates, END=dates, key=c("START", "END")) 

## 2. Now find overlapping coordinates 
# for each row in `df` get all the rows it overlaps with in `lookup` 
ans = foverlaps(df, lookup, type="any", which=TRUE) 

Bây giờ, chúng tôi chỉ có vào nhóm bởi yid (= chỉ số trong lookup) và đếm:

## 3. count 
ans[, .N, by=yid] 
# yid N 
# 1: 1 1 
# 2: 2 2 
# 3: 3 4 
# 4: 4 2 

Cột đầu tiên tương ứng với số hàng trong lookup. Nếu một số số bị thiếu, thì số đếm là 0 cho chúng.

+1

Đây là trường hợp tham gia chồng chéo bằng cách sử dụng 'foverlaps()' bằng cách tạo một dữ liệu khác. Có thể với ngày mong muốn OP muốn tìm các chồng chéo cho. Bạn có muốn thử không. – Arun

+0

@Arun Cảm ơn bạn đã chỉnh sửa và hiển thị 'foverlaps'. – akrun

+0

Lòng tốt của tôi.Là một người dùng R mới, tôi ngạc nhiên trước nhiều phương pháp có sẵn để giải quyết các câu hỏi như vậy. Tôi có một số bắt kịp để làm. Ngoài ra, nhờ Richard Scriven để làm rõ câu hỏi của tôi. Tôi rất cảm kích sự giúp đỡ của tất cả mọi người. Điều này thật tuyệt vời. –

1

Sử dụng dplyr và dữ liệu theo nhóm:

data_frame(
      START = as.Date(c("2014-01-01", "2014-01-02","2014-01-03","2014-01-03")), 
      END = as.Date(c("2014-01-04", "2014-01-03","2014-01-03","2014-01-04")) 
      ) -> df 
rbind(cbind(group = 'a', df),cbind(group = 'b', df)) %>% as_data_frame->df 
df 

df %>% 
    group_by(.,group) %>% 
    do(data.frame(table(Reduce(c, Map(seq, .$START, .$END, by = 1))))) 

Đây là một vấn đề thường gặp khi bạn ví dụ muốn tìm số lần đăng nhập trên các trang/máy khác nhau vv cho thời gian khoảng trên mỗi người dùng

> df 
Source: local data frame [8 x 3] 

    group  START  END 
    (chr)  (date)  (date) 
1  a 2014-01-01 2014-01-04 
2  a 2014-01-02 2014-01-03 
3  a 2014-01-03 2014-01-03 
4  a 2014-01-03 2014-01-04 
5  b 2014-01-01 2014-01-04 
6  b 2014-01-02 2014-01-03 
7  b 2014-01-03 2014-01-03 
8  b 2014-01-03 2014-01-04 
> 
> df %>% 
+ group_by(.,group) %>% 
+ do(data.frame(table(Reduce(c, Map(seq, .$START, .$END, by = 1))))) 
Source: local data frame [8 x 3] 
Groups: group [2] 

    group  Var1 Freq 
    (chr)  (fctr) (int) 
1  a 2014-01-01  1 
2  a 2014-01-02  2 
3  a 2014-01-03  4 
4  a 2014-01-04  2 
5  b 2014-01-01  1 
6  b 2014-01-02  2 
7  b 2014-01-03  4 
8  b 2014-01-04  2 
0

Sử dụng dplyrforeach:

library(dplyr) 
library(foreach) 

df <- data.frame(START = as.Date(c("2014-01-01", 
            "2014-01-02", 
            "2014-01-03", 
            "2014-01-03")), 
       END = as.Date(c("2014-01-04", 
           "2014-01-03", 
           "2014-01-03", 
           "2014-01-04"))) 
df 

r <- foreach(DATETIME = seq(min(df$START), max(df$END), by = 1), 
      .combine = rbind) %do% { 
    df %>% 
    filter(DATETIME >= START & DATETIME <= END) %>% 
    summarise(DATETIME, COUNT = n()) 
} 
r 
Các vấn đề liên quan