2015-10-07 30 views
11

Çözmeyi denediğim sorun, içinde sıralanmış bir POSIXct değişkenine sahip bir veri çerçevem ​​var. Her satır kategorize edilir ve her seviye için her bir satır arasındaki zaman farklarını almak ve bu verileri tekrar yeni bir değişkene eklemek istiyorum. Tekrarlanabilir problem aşağıdaki gibidir. Aşağıdaki işlev, bu sorunun amacı için sadece rastgele zamanlarla örnek veri oluşturmak içindir.Bir satır ile bir satır arasındaki bir önceki satır arasındaki zaman farkının nasıl hesaplanacağı düzeyler

random.time <- function(N, start, end) { 
    st <- as.POSIXct(start) 
    en <- as.POSIXct(end) 
    dt <- as.numeric(difftime(en, st, unit="sec")) 
    ev <- sort(runif(N, 0, dt)) 
    rt <- st + ev 
    return(rt) 
} 

sorun simüle etmek için kod, aşağıdaki gibidir:

set.seed(123) 
category <- sample(LETTERS[1:5], 20, replace=TRUE) 
randtime <- random.time(20, '2015/06/01 08:00:00', '2015/06/01 18:00:00') 
df <- data.frame(category, randtime) 

veri çerçevesini elde edilen aşağıdaki gibidir: beklenen:

>category randtime timediff (secs) 
>A 2015-06-01 09:05:00 0 
>A 2015-06-01 09:06:30 90 
>A 2015-06-01 09:10:00 210 
>B 2015-06-01 10:18:58 0 
>B 2015-06-01 10:19:58 60 
>C 2015-06-01 08:14:00 0 
>C 2015-06-01 08:16:30 150 

çıkışı her alt grup ilk satırı vardır Önceki satır olmadığı için 0 zaman değeriyle. Kategorilere göre gruplama yapabildim ve farklılıkları hesaplamak için aşağıdaki işlevi çağırdım ancak tüm kategori grupları için son çıktıyı harmanlayamadım.

getTimeDiff <- function(x) { 
    no_rows <- nrow(x) 
    if(no_rows > 1) { 
    for(i in 2:no_rows) { 
     t <- x[i, "randtime"] - x[i-1, "randtime"] 
    } 
    } 
} 

Şanssız iki gün boyunca burada bulundum, bu yüzden herhangi bir yardımı çok takdir ediyorum. Teşekkürler.

cevap

10

bu deneyin:

library(dplyr) 
df %>% 
    arrange(category, randtime) %>% 
    group_by(category) %>% 
    mutate(diff = randtime - lag(randtime), 
     diff_secs = as.numeric(diff, units = 'secs')) 

# category   randtime    diff diff_secs 
#  (fctr)    (time)   (dfft)  (dbl) 
# 1  A 2015-06-01 11:10:54   NA hours   NA 
# 2  A 2015-06-01 15:35:04 4.402785 hours 15850.027 
# 3  A 2015-06-01 17:01:22 1.438395 hours 5178.222 
# 4  B 2015-06-01 08:14:46   NA hours   NA 
# 5  B 2015-06-01 16:53:43 518.955379 hours 1868239.364 
# 6  B 2015-06-01 17:37:48 44.090950 hours 158727.420 

Ayrıca zincire replace(is.na(.), 0) eklemek isteyebilir.

+0

sayesinde. Bu, kısmen, çıktıyı gereken şekilde düzenlemek için çözer. Bununla birlikte, lag() bir önceki satırın zamanını gerçek fark değil, zaman değeri olarak döndürür. – Mntester

+0

@Mntester düzeltildi. – JasonAizkalns

9

baz Ar size kullanabilirsiniz:

# creating an ordered data.frame 
df <- data.frame(category, randtime) 
df <- df[order(df$category, df$randtime),] 
# calculating the timedifference 
df$tdiff <- unlist(tapply(df$randtime, INDEX = df$category, 
          FUN = function(x) c(0, `units<-`(diff(x), "secs")))) 

veren: Eğer birkaç dakika veya saat istiyorsanız

> df 
    category   randtime  tdiff 
6   A 2015-06-01 11:10:54  0.0000 
15  A 2015-06-01 15:35:04 15850.0271 
18  A 2015-06-01 17:01:22 5178.2223 
1   B 2015-06-01 08:14:46  0.0000 
17  B 2015-06-01 16:53:43 31137.3227 
19  B 2015-06-01 17:37:48 2645.4570 
3   C 2015-06-01 10:09:50  0.0000 
7   C 2015-06-01 12:46:40 9409.9693 
9   C 2015-06-01 13:56:29 4188.4578 
10  C 2015-06-01 14:24:18 1669.1326 
12  C 2015-06-01 14:54:25 1807.1447 
14  C 2015-06-01 15:05:07 641.7068 
2   D 2015-06-01 09:28:16  0.0000 
13  D 2015-06-01 14:55:40 19644.8313 
4   E 2015-06-01 10:18:58  0.0000 
5   E 2015-06-01 10:53:29 2071.2223 
8   E 2015-06-01 13:26:26 9176.6263 
11  E 2015-06-01 14:33:25 4019.0319 
16  E 2015-06-01 15:57:16 5031.4183 
20  E 2015-06-01 17:56:33 7156.8849 

, sen "mins" veya "hours" kullanmak yerine "secs" edebilirsiniz.


data.table paketi ile alternatif:

library(data.table) 
# creating an ordered/keyed data.table 
dt <- data.table(category, randtime, key = c("category", "randtime")) 
# calculating the timedifference 
dt[, tdiff := difftime(randtime, shift(randtime, fill=randtime[1L]), units="secs"), by=category] 
# or: 
dt[, tdiff := c(0, `units<-`(diff(randtime), "secs")), by = category] 

sonuçlanır: Hızlı cevap için

> dt 
    category   randtime   tdiff 
1:  A 2015-06-01 11:10:54  0.0000 secs 
2:  A 2015-06-01 15:35:04 15850.0271 secs 
3:  A 2015-06-01 17:01:22 5178.2223 secs 
4:  B 2015-06-01 08:14:46  0.0000 secs 
5:  B 2015-06-01 16:53:43 31137.3227 secs 
6:  B 2015-06-01 17:37:48 2645.4570 secs 
7:  C 2015-06-01 10:09:50  0.0000 secs 
8:  C 2015-06-01 12:46:40 9409.9693 secs 
9:  C 2015-06-01 13:56:29 4188.4578 secs 
10:  C 2015-06-01 14:24:18 1669.1326 secs 
11:  C 2015-06-01 14:54:25 1807.1447 secs 
12:  C 2015-06-01 15:05:07 641.7068 secs 
13:  D 2015-06-01 09:28:16  0.0000 secs 
14:  D 2015-06-01 14:55:40 19644.8313 secs 
15:  E 2015-06-01 10:18:58  0.0000 secs 
16:  E 2015-06-01 10:53:29 2071.2223 secs 
17:  E 2015-06-01 13:26:26 9176.6263 secs 
18:  E 2015-06-01 14:33:25 4019.0319 secs 
19:  E 2015-06-01 15:57:16 5031.4183 secs 
20:  E 2015-06-01 17:56:33 7156.8849 secs 
+0

Evet, her iki çözüm de harika çalışıyor. Hepinize çok teşekkürler. – Mntester

+0

@Mntester, bir R taban çözümü ile cevabı genişletti – Jaap

+0

Birden fazla vesile olabilirdim, böyle güzel, temiz bir 'data.table' çözümü! Not: first_removed <- dt [dt [, -.I [1], by = kategori] $ V1] 'seçeneğini kullanarak, sonuçta elde edilen data.table tablosundan kategori başına ilk satırı kaldırmak için kullanıyorum. bir özellik olarak fark, bu yüzden sıfırları istemiyorum). – Bar

İlgili konular