2

常にレベルX、Y、またはZのいずれかにある3つのプロセスA、B、およびCを監視しています。プロトコルは、プロセスがレベル​​を変更したときに記録します。

df = read.csv(tc <- textConnection('Time1,Process1,Level1
2013-01-09 18:00:34,A,X
2013-01-09 18:00:34,B,Y
2013-01-09 18:00:34,C,X
2013-01-09 22:00:59,A,Z
2013-01-10 00:10:38,A,X
2013-01-10 18:38:35,B,Z
2013-01-11 05:03:11,A,Z
2013-01-11 11:09:10,C,Y
2013-01-11 12:01:18,A,Off
2013-01-11 12:01:18,B,Off
2013-01-11 12:01:18,C,Off
'),header=TRUE)
close.connection(tc) 
df$Time1 = as.POSIXct(df$Time1)

監視は2013-01-0918:00:34に開始され、2013-01-1112:01:18にオフになりました。2013-01-0918:00:34と2013-01-0922:00:59の間プロセスAはレベルXで、2013-01-0922:00:59と2013-01-10000:10の間: 38プロセスAはレベルZにありました。

グラフ化の目的で、各深夜の各プロセスの最後と最初のレベルの状態をプロトコルに挿入します。

2013-01-09 23:59:59,A,Z
2013-01-10 00:00:00,A,Z
2013-01-10 23:59:59,A,X
2013-01-11 00:00:00,A,X

2013-01-09 23:59:59,B,Y
2013-01-10 00:00:00,B,Y
2013-01-10 23:59:59,B,Z
2013-01-11 00:00:00,B,Z

2013-01-09 23:59:59,C,X
2013-01-10 00:00:00,C,X
2013-01-10 23:59:59,C,X
2013-01-11 00:00:00,C,X

23:59:59から00:00:00の間にログにイベントがないと想定しても問題ありません。最後に、プロトコルは挿入後にTime1でソートされます(自分で理解できます)。どんな指導も大歓迎です!

4

1 に答える 1

2

(+1) 非常に複雑で興味深いタスク。私は答えを持っていると思います。ここでその方法を説明しようと思います。それが理にかなっていることを願っています。ここには 2 つのトリッキーなビットがあります。私のソリューションはを使用しdata.tableます。

First:最初に、必要な出力の最初の 2 列を作成する方が簡単であることがわかりました。これは、以下に示すコードの最初の部分で行われます。

require(data.table)
dates <- unique(as.character(strptime(as.character(df$Time1), "%Y-%m-%d")))
dates <- dates[1:(length(dates)-1)]
dates <- strptime(paste(dates, "23:59:59"), "%Y-%m-%d %H:%M:%S")
dates <- sort(c(dates, dates+1))
Time <- rep(dates, length(levels(df$Process1)))
Process <- rep(levels(df$Process1), each=length(dates))
dt.out <- data.table(Time=as.POSIXct(Time), Process=Process)
# data.table outputs crazy values if not converted using as.POSIXct..?!

これは、コードの各行が何をするかを見れば簡単に理解できるはずです。他のシナリオにも拡張できることを願っています。

Second:2 番目のビットも同様にトリッキーですが、 を使用して 1 行で実行できますdata.table。理解するのに時間がかかりましたが、素晴らしいです!

dt <- data.table(df, key="Process1") # convert input data.frame to data.table
out <- dt.out[, dt[J(Process)]$Level1[max(which(dt[J(Process)]$Time1 < Time))], 
            by = c("Process", "Time")]

> out

    Process                Time V1
 1:       A 2013-01-09 23:59:59  Z
 2:       A 2013-01-10 00:00:00  Z
 3:       A 2013-01-10 23:59:59  X
 4:       A 2013-01-11 00:00:00  X
 5:       B 2013-01-09 23:59:59  Y
 6:       B 2013-01-10 00:00:00  Y
 7:       B 2013-01-10 23:59:59  Z
 8:       B 2013-01-11 00:00:00  Z
 9:       C 2013-01-09 23:59:59  X
10:       C 2013-01-10 00:00:00  X
11:       C 2013-01-10 23:59:59  X
12:       C 2013-01-11 00:00:00  X

何が起こっているのかを説明するために、これらの 2 つの行を部分に分けてみましょう。

最初の行ではset keydtasを使用しProcess1ます。これによりVERY fast、列によるデータのフィルタリングが可能になりますProcess1。つまり、dt["A"]は と同等ですdf[df$Process1 == "A"]が、前者は非常に高速です。

2行目では、かなり多くのことが起こっています。dt.out必要な出力の最初の 2 つの列を既に作成しています。残っているのは 3 番目の列だけです。という行の最後の部分を見てくださいby = c("Process", "Time")。ここではdata.table dt.out、これら 2 つの変数で分割しています。そして、 split のそれぞれdata.tableに適用します。dt[J(Process)]$Level1[max(which(dt[J(Process)]$Time1 < Time))]これは基本的に、フィルタリングされたものから<であるmaximum indexすべての現在の値から を選択し、この最大インデックスを使用して対応する値を返します。Time1Timedata.tableProcessLevels1

お役に立てれば。

于 2013-01-15T15:00:14.383 に答える