2016-05-27 3 views
0

私は、カテゴリステータスを指定するタイムスタンプのデータフレームを持っています。ステータスは、次のタイムスタンプまで有効で、その時点でカテゴリが変更される可能性があります。時系列のカテゴリデータ - 各カテゴリの割合を時間の経過とともにどのように計算するか?

私は毎年、毎月、四半期ごとなど定期的な期間にわたって各カテゴリに費やされた時間の割合を決定することができるようにしたいと思います。

これは一般的な十分な問題のように思えるが、私はそれを解決するためのエレガントなソリューションまたはライブラリを見つけることができませんしてきました。

たとえば、次のサンプルデータフレームで:

  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')) 
+0

回答が確認できるようにサンプル入力に望ましい出力を与えると役立ちます。あなたの日付/時間列の 'diff()'を取り、それを対応するステータス(終了時刻がない最後のステータスを無視して)で集めることができるように思えます。インターバル・ブレークをどのように選択しているのか、それらのインターバルにまたがる時間に対して何をしたいのかを示すことが重要です。 – MrFlick

+0

'do.call(rbind、tapply(df $ date、months df $ date)、function(x){prop.table(table(x))* 100})))')のようなもの、おそらく – alistaire

+0

@alistaireデータセットが複数年にわたる場合は、異なる月の同じ月が一緒に集計されるため、機能しません。 'months()'呼び出しを 'format()'に置き換えて、年と月の両方を含めることができました。 '書式(df $ date、 '%Y-%m')'となります。 – bgoldst

答えて

0

は、ネストされたdata.table凝集にcut.POSIXt() S3の特定を組み合わせたアプローチです。

## define data 
library(data.table); 
dt <- data.table(date=as.POSIXct(c('2016-02-20 09:11:00','2016-03-06 02:38:00','2016-03-10 15:20:00','2016-03-10 21:20:00','2016-03-11 11:51:00','2016-03-12 01:19:00','2016-03-22 14:39:00','2016-03-23 11:37:00','2016-03-25 17:38:00','2016-03-26 01:24:00','2016-03-26 12:40:00','2016-04-12 10:28:00')),status=c('a','c','b','a','b','c','c','b','c','c','a','c')); 

## solution 
dt[,{ n1 <- .N; .SD[,.(pct=.N/n1*100),.(status)]; },.(month=cut(df$date,'month'))]; 
##   month status pct 
## 1: 2016-02-01  a 100 
## 2: 2016-03-01  c 50 
## 3: 2016-03-01  b 30 
## 4: 2016-03-01  a 20 
## 5: 2016-04-01  c 100 
関連する問題