私は顧客IDの列、購入日の列、および列を持つdata.tableを持っていますその購入額を私がしたいことは、顧客の間で毎日の購入価値の平均を計算し、欠損値を次の利用可能な値で埋めることです。data.table列の(locf/nocb)値を効率的に記入し、別の列で集計します
わかりやすくするために、最小限の例では重複する日はありません。
library(data.table)
dat <- data.table(custid=rep(seq(10),5), day=sample(50), val=rnorm(50,0,1))[order(custid,day)]
これを解決する方法はわかっていますが、効率的に行う方法はわかりません。一つの解決策は、欠損値がzoo
からna.locf()
を使用して、後方次の観察を運ぶために、その後NAとなり、そのようdata.tableを拡大することです:
library(zoo)
res <- dat[as.data.table(expand.grid(custid=seq(10), day=seq(50))), on=c('custid','day'), allow.cartesian=TRUE, nomatch=NA][order(custid,day)]
res[, val:=na.locf(val, fromLast=TRUE, na.rm=FALSE), by='custid']
res <- res[,list(meanVal=mean(val, na.rm=TRUE)), by='day']
多くの日がある場合ただし、これは非常に大きなテーブルを作成し、多くの顧客が、ほとんどの顧客はたった数日で購入しました。だから私はそれを望んでいない。
別の解決策は、一日あたりの日、フィルタと集計をループにし、再度data.tableに行をバインドします
res2 <- list()
for (dy in seq(max(dat$day))) {
res2 <- c(res2,
list(dat[day>=dy, .SD[1], by='custid'][,list(day=dy, meanVal=mean(val, na.rm=T))]))
}
res2 <- rbindlist(res2)
しかし、これは遅いです。
誰も、遅いループや大規模な中間テーブルの作成を必要としないdata.tableソリューションを考え出すことができますか?私の限られたテストで
'aggregate(dat、list(dat $ day)、mean)[、c( 'day'、 'val')]'あなたは何をしたいですか? – Ryan
平均化する前にNAsを次の値に置き換えたい場合は、直接dat [is.na(dat $ val)、] $ val < - dat [which(na) )+ 1、] $ val' – Ryan