私は、カテゴリステータスを指定するタイムスタンプのデータフレームを持っています。ステータスは、次のタイムスタンプまで有効で、その時点でカテゴリが変更される可能性があります。時系列のカテゴリデータ - 各カテゴリの割合を時間の経過とともにどのように計算するか?
私は毎年、毎月、四半期ごとなど定期的な期間にわたって各カテゴリに費やされた時間の割合を決定することができるようにしたいと思います。
これは一般的な十分な問題のように思えるが、私はそれを解決するためのエレガントなソリューションまたはライブラリを見つけることができませんしてきました。
たとえば、次のサンプルデータフレームで:
date status
2016-02-20 09:11:00 a
2016-03-06 02:38:00 c
2016-03-10 15:20:00 b
2016-03-10 21:20:00 a
2016-03-11 11:51:00 b
2016-03-12 01:19:00 c
2016-03-22 14:39:00 c
2016-03-23 11:37:00 b
2016-03-25 17:38:00 c
2016-03-26 01:24:00 c
2016-03-26 12:40:00 a
2016-04-12 10:28:00 c
...私は3/15〜3/8-3/14、3/1-3/7から毎週報告することがあります3/21、「a」、「b」、「c」ステータスの各週のパーセント時間。
私は多分決めたとき、私はそれを行うには、よりエレガントな方法があるのかどうかをここで確認する必要があり、(それは醜いです...)これに対する解決策をコーディングブルートフォースを開始しました。編集
======== は、サンプルの使用であろう以下 ========
time_analysis <- function(df, starttime, endtime) {
# - assumes sorted by date
startindex <- sum(df$date <= starttime) # find the index of the entry which contains the start time
endindex <- sum(df$date <= endtime) + 1 # find the index of the entry which contains the end time
if ((startindex == 0) || (endindex > nrow(df))) {
print("Date outside of available data")
return(NULL)
}
df2 <- df[ startindex:endindex, ] # subset the dataframe to include the range, but still need to trim ends
df2$date[1] <- starttime # trim to the start time
df2$date[nrow(df2)] <- endtime # trim back the end time
df2$status[nrow(df2)] <- df2$status[nrow(df2)-1] # status hasn't changed yet, so still the previous status
duration <- diff(df2$date) # vector of the time within each segment, 1 fewer elements than the dataframe
units(duration) <- 'days'
duration <- as.numeric(duration) # need to convert to numeric, or else can't divide by total duration
df2 <- df2[ -nrow(df2), ] # remove the last row, to make length same as the duration vector
df2$duration <- duration # add the duration column
total <- sum(df2$duration) # to allow calculations within the ddply
return(ddply(df2[, c('status','duration')], 'status', function(x) { # calculate by each status category
return(c(
date = starttime,
totaldays = round(sum(x$duration), 2),
fraction = round(sum(x$duration)/total, 3)))
}))
}
下に洗練ブルートフォース溶液を追加してし報告書を約2週間分に分割することになります。私は手動の日付のコーディングを使用して、Rのループを使用するのは嫌いですが、あまりにも経験のない方が良い方法を知っています。 (範囲外の日付のためのいくつかのエラー以外)降伏
times <- c("2016-03-01","2016-03-15","2016-04-01","2016-04-15","2016-05-01","2016-05-15")
result <- data.frame()
for (i in 1:(length(times) - 1)) {
result <- rbind(result, time_analysis(d, times[i], times[i+1]))
}
print(result, row.names = FALSE)
:
:status date totaldays fraction
a 2016-03-01 5.71 0.409
b 2016-03-01 0.81 0.058
c 2016-03-01 7.43 0.532
a 2016-03-15 5.47 0.322
b 2016-03-15 2.25 0.132
c 2016-03-15 9.28 0.546
===== ポスティングした後は、時間を生成するために非常に良く方法を見つけましたここで
times <- as.character(seq(as.Date("2016-03-01"), as.Date("2016-05-15"), by = '2 weeks'))
回答が確認できるようにサンプル入力に望ましい出力を与えると役立ちます。あなたの日付/時間列の 'diff()'を取り、それを対応するステータス(終了時刻がない最後のステータスを無視して)で集めることができるように思えます。インターバル・ブレークをどのように選択しているのか、それらのインターバルにまたがる時間に対して何をしたいのかを示すことが重要です。 – MrFlick
'do.call(rbind、tapply(df $ date、months df $ date)、function(x){prop.table(table(x))* 100})))')のようなもの、おそらく – alistaire
@alistaireデータセットが複数年にわたる場合は、異なる月の同じ月が一緒に集計されるため、機能しません。 'months()'呼び出しを 'format()'に置き換えて、年と月の両方を含めることができました。 '書式(df $ date、 '%Y-%m')'となります。 – bgoldst