2015-10-07 9 views
11

私が解決しようとしている問題は、ソートされたPOSIXct変数を持つデータフレームがあることです。各行は分類されており、各レベルの各行間の時間差を求め、そのデータを新しい変数に戻したいと考えています。再現可能な問題は以下の通りです。 以下の関数は、この質問の目的でランダムな時刻のサンプルデータを作成するためのものです。 レベルによってdata.frameの行と前の行の時間差を計算する方法

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) 
} 

問題をシミュレートするためのコードは以下の通りである:

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) 

予想される結果のデータフレームは、以下の通りである:

>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 

出力の各サブグループは、最初の行を有することになります前の行がないのでtimediff値は0です。カテゴリ別にグループ化し、次の関数を呼び出して差異を計算することはできましたが、すべてのカテゴリグループの最終出力を照合することができませんでした。

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"] 
    } 
    } 
} 

私はこの2日間、運がなかったので、どんな助けにも大いに感謝しています。おかげさまで

答えて

10

これを試してみてください:

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 

はまた、チェーンにreplace(is.na(.), 0)を追加することもできます。あなたが使用することができ、ベースRで

+0

感謝。これは、必要に応じて出力を配列する際に部分的に解決します。しかし、lag()は前の行の時刻をtimediffの値として返しますが、実際の値の差は返しません。 – Mntester

+0

@Meterが修正されました。 – JasonAizkalns

9

# 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")))) 

います:

> 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 

を使用すると、数分または数時間が必要な場合は、あなたの代わりに"secs""mins"または"hours"を使用することができます。


data.tableパッケージと代替:

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] 

になり:迅速な対応のための

> 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

はい、これらのソリューションはどちらも優れています。ありがとう、皆さん。 – Mntester

+0

@Mntesterは基底R解で答えを拡張しました – Jaap

+0

欲しい私は複数のupvoteを持つことができました。そのようなきれいな、きれいな 'data.table'ソリューション!注意してください。必要に応じて、結果のdata.tableからカテゴリごとの最初の行を削除するには 'first_removed < - dt [、-.I [1]、by = category] ​​$ V1]'を使用してください。私はゼロを望んでいません)。 – Bar

関連する問題