3

次のコマンドで生成されたデータ フレームがあるとします。

date <- seq(as.Date("2012-09-01"), Sys.Date(), 1)
id <- rep(c("a","b","c","d"), 8)
bdate <- seq(as.Date("2012-08-01"), as.Date("2012-11-01"), 1)[sample(1:32, 32)]

# The end date should be random but greater than the begin date. However, I set it to 15 days later for simplicity.
edate <- bdate + 15

value <- seq(1, 1000, 1)[sample(1:1000, 32)]
dfa <- data.frame(id, value, bdate, edate)
names(dfa) <- c("ID", "Value", "Begin.Date", "End.Date")

目標は、次の方法で ID (つまり、「a」、「b」、または「c」) ごとにすべての観測値を合計することです。

Date        a   b   c
2012-08-01  XXX YYY ZZZ
2012-08-02  XXX YYY ZZZ
2012-08-03  XXX YYY ZZZ

値 XXX、YYY、および ZZZ は、ID ごとに、列 "Date" の日付が元のデータ フレームの dfa$Begin.Date と dfa$End.Date の間にあるすべての観測値の合計を表します。

私の現在のソリューションは、大規模なデータセットには実質的に役に立たないので、より高速な方法があるかどうか疑問に思っていました.

私の現在のスクリプト:

# Create additional data frame
dfb <- data.frame(seq(as.Date("2012-08-01"), as.Date("2012-11-01"), 1))
names(dfb)[1] <- "Date"

# Variable for unique IDs
nid <- unique(dfa$ID)

# Number of total IDs
tid <- length(nid)

for (i in c(1:tid))
{
sums <- vapply(dfb$Date, function(x)
{
temp <- subset(dfa, dfa$ID == nid[i])
temp <- subset(temp, temp$Begin.Date < x & temp$End.Date > x)
res <- sum(temp$Value)
res
}, FUN.VALUE = 0.1
)
dfb[1+i] <- sums
}

# Change column names to ID
names(dfb) <- c("Date", as.character(nid))

編集:これを行うためのより効率的な方法で、以下の回答を投稿しました。ただし、マシューの答えは正しい道を示してくれたので、受け入れました。

4

4 に答える 4

3

@Matthew Dowle のおかげで、data.table パッケージを使用してこれをより効率的に行う方法を見つけました。

# Fire up the bad boy
library(data.table)

# Create the data table with original data
value <- seq(1, 1000, 1)[sample(1:1000, 32)]
dt <- data.table(id, value, bdate, edate)
setnames(dt, names(dt), c("id", "value", "begin", "end"))

# For each pair of id and value, create a row for each day. (i.e., the first line:
# a  928  2012-08-11  2012-08-26
# will now be 15 lines. The first two columns are repeated over 15 different dates.
dt <- dt[, seq(begin[1], (last(end) - 1), by="days"), by = list(id, value)]
setnames(dt, names(dt), c(names(dt)[1:2], "date"))
setkey(dt)

# Sum each pair of id and value over the dates column
dt <- dt[, sum(value), by = list(id, date)]
setnames(dt, names(dt), c(names(dt)[1:2], "value"))
setkey(dt, date, id)

# Define the time span you would like on your final table
timespan <- dt[, seq(as.Date("2012-07-25"), max(date), by = "day")]

# Now just cross reference the time span with your actual data
setkey(dt, id, date)
dt <- dt[CJ(unique(id), timespan), ]
setnames(dt, names(dt), c(names(dt)[1:2], "value"))
setkey(dt, date)

タダ!!

さて、私が最初に望んでいた順序でテーブルを再配置するには:

Date        a   b   c
2012-08-01  XXX YYY ZZZ
2012-08-02  XXX YYY ZZZ
2012-08-03  XXX YYY ZZZ

reshape2 パッケージの dcast を使用するだけです。

それで、皆さんはどう思いますか?すごいですよね?

于 2012-10-12T19:51:45.633 に答える
2

面白い。この質問に非常に似ているようです:

不規則な時系列を通常の月平均に分割する

それは役に立ちますか?そこでは、あなたの質問のように、 in packagebeginを使用する一般的な方法に参加することが 1 つの秘訣です。特に、大規模なデータセットがあると述べたので。roll=TRUEdata.table

于 2012-10-05T13:36:05.653 に答える
0

私は次のことをします。Begin.Date最初に、目的の日付が ~ の間にあるかどうかを確認して、元のデータ セットをサブセット化しEnd.Dateます。次に、単純な関数を使用して、スルーtableの周波数を取得します。'a''d'

mydate <- as.Date("2012-08-25")  # take Aug 25, 2012 as an example
ind <- (dfa$Begin.Date <= mydate) & (dfa$End.Date >= mydate)
temp <- subset(dfa, ind)
out <- table(temp$ID)
于 2012-10-02T19:21:10.757 に答える
-1

これがより高速であるかどうかはわかりません(ベンチマークを行っていません)。特に大きなデータの場合、中間データセットが大きすぎる可能性がありますが、とにかく提示します。

考慮される日付の範囲も設定できます(この回答へのコメントに基づく要求)。

library("plyr")
library("reshape2")

earliest.date <- as.Date("2007-01-01")
latest.date <- as.Date("2012-11-01")

dfa.long <- adply(dfa, 1, function(DF) {
  if(DF$End.Date >= earliest.date & DF$Begin.Date <= latest.date) {
    data.frame(Date=seq(max(DF$Begin.Date, earliest.date), 
                        min(DF$End.Date, latest.date), 
                        1))
  }
})

dfb <- ddply(dfa.long, .(Date, ID), summarise, sum=sum(Value))
dfb <- dcast(dfb, Date~ID, value.var="sum", fill=0)

dfa.longは、開始/終了範囲内の日付ごとに各行が繰り返されるデータセットです(最も早い/最も遅い日付範囲内にも制限されます)。次に、日付ごとに集計し、fromをID使用して希望のワイドフォーマットに変換するのは簡単です。dcastreshape2

于 2012-10-02T19:29:50.893 に答える