2013-02-06 41 views
28

Tôi đã viết một hàm (khá ngây thơ) để chọn ngẫu nhiên một ngày/giờ giữa hai ngày quy địnhhiệu quả tạo ra một mẫu ngẫu nhiên của thời gian và ngày giữa hai ngày

# set start and end dates to sample between 
day.start <- "2012/01/01" 
day.end <- "2012/12/31" 

# define a random date/time selection function 
rand.day.time <- function(day.start,day.end,size) { 
    dayseq <- seq.Date(as.Date(day.start),as.Date(day.end),by="day") 
    dayselect <- sample(dayseq,size,replace=TRUE) 
    hourselect <- sample(1:24,size,replace=TRUE) 
    minselect <- sample(0:59,size,replace=TRUE) 
    as.POSIXlt(paste(dayselect, hourselect,":",minselect,sep="")) 
} 

mà kết quả trong:

> rand.day.time(day.start,day.end,size=3) 
[1] "2012-02-07 21:42:00" "2012-09-02 07:27:00" "2012-06-15 01:13:00" 

Nhưng điều này dường như chậm lại đáng kể khi kích thước mẫu tăng lên.

# some benchmarking 
> system.time(rand.day.time(day.start,day.end,size=100000)) 
    user system elapsed 
    4.68 0.03 4.70 
> system.time(rand.day.time(day.start,day.end,size=200000)) 
    user system elapsed 
    9.42 0.06 9.49 

Có ai có thể đề xuất cách làm điều gì đó như thế này một cách hiệu quả hơn không?

Trả lời

39

Ahh, một ngày/giờ vấn đề chúng ta có thể giảm được làm việc trong nổi :)

Hãy thử chức năng này

R> latemail <- function(N, st="2012/01/01", et="2012/12/31") { 
+  st <- as.POSIXct(as.Date(st)) 
+  et <- as.POSIXct(as.Date(et)) 
+  dt <- as.numeric(difftime(et,st,unit="sec")) 
+  ev <- sort(runif(N, 0, dt)) 
+  rt <- st + ev 
+ } 
R> 

Chúng tôi tính toán difftime trong vài giây, và sau đó "chỉ đơn thuần là" vẽ đồng phục trên nó , sắp xếp kết quả. Thêm điều đó vào đầu và bạn đã hoàn tất:

R> set.seed(42); print(latemail(5))  ## round to date, or hour, or ... 
[1] "2012-04-14 05:34:56.369022 CDT" "2012-08-22 00:41:26.683809 CDT" 
[3] "2012-10-29 21:43:16.335659 CDT" "2012-11-29 15:42:03.387701 CST" 
[5] "2012-12-07 18:46:50.233761 CST" 
R> system.time(latemail(100000)) 
    user system elapsed 
    0.024 0.000 0.021 
R> system.time(latemail(200000)) 
    user system elapsed 
    0.044 0.000 0.045 
R> system.time(latemail(10000000)) ## a few more than in your example :) 
    user system elapsed 
    3.240 0.172 3.428 
R> 
+0

Chúc mừng - làm việc một điều trị và nhanh chóng. – thelatemail

+10

Quy tắc đầu tiên về làm việc với ngày và giờ: * luôn luôn * hãy nhớ rằng 'POSIXct' thực sự chỉ là một số có số giây phân số từ theepoch. Dito cho 'Ngày' và các ngày phân số. Rất nhiều vấn đề trở thành * rất nhiều * dễ dàng hơn theo cách đó. –

+4

Thiên tài của câu trả lời này là thủ thuật 'st + ev' - đó là vòng tròn tới' POSIXct' gây đau đớn, vì bạn cần xác định rõ nguồn gốc. Nếu không 'runif (N, as.POSIXct (st), as.POSIXct (et))' sẽ cho bạn 90% số này; nhưng sau đó bạn cần 'as.POSIXct (..., origin =" 1970-01-01 ")' – user295691

2

Điều gì đó tương tự cũng sẽ hoạt động. Xin lỗi cho khung dữ liệu ngẫu nhiên, tôi chỉ ném nó vào đó để bạn có thể thấy một âm mưu.

data=as.data.frame(list(ID=1:10, 
        variable=rnorm(10,50,10))) 

#This function will generate a uniform sample of dates from 
#within a designated start and end date: 

rand.date=function(start.day,end.day,data){ 
    size=dim(data)[1]  
    days=seq.Date(as.Date(start.day),as.Date(end.day),by="day") 
    pick.day=runif(size,1,length(days)) 
    date=days[pick.day] 
} 

#This will create a new column within your data frame called date: 

data$date=rand.date("2014-01-01","2014-02-28",data) 

#and this will order your data frame by date: 

data=data[order(data$date),] 

#Finally, you can see how the data looks 

plot(data$date,data$variable,type="b") 
Các vấn đề liên quan