7

エネルギー使用量に対する季節的な影響を確認するには、請求データベースから取得したエネルギー使用量情報を月ごとの気温に合わせる必要があります。

さまざまな長さの請求書と開始日と終了日を持つ請求データセットを使用しています。各月の各アカウントの月平均を取得したいと思います。たとえば、次の特性を持つ課金データベースがあります。

   acct amount      begin        end days
1  2242  11349 2009-10-06 2009-11-04   29
2  2242  12252 2009-11-04 2009-12-04   30
3  2242  21774 2009-12-04 2010-01-08   35
4  2242  18293 2010-01-08 2010-02-05   28
5  2243  27217 2009-10-06 2009-11-04   29
6  2243    117 2009-11-04 2009-12-04   30
7  2243  14543 2009-12-04 2010-01-08   35

これらのやや不規則な時系列(アカウントごと)を強制して、各請求書にまたがる各月の1日あたりの平均金額を取得する方法を理解したいと思います。

   acct amount      begin        end days avgamtpday
1  2242  11349 2009-10-01 2009-10-31   31          X
2  2242  12252 2009-11-01 2009-11-30   30          X
3  2242  21774 2009-12-01 2010-12-31   31          X
4  2242  18293 2010-01-01 2010-01-31   31          X
4  2242  18293 2010-02-01 2010-02-28   28          X
5  2243  27217 2009-10-01 2009-10-31   31          X
6  2243    117 2009-11-01 2009-11-30   30          X
7  2243  14543 2009-12-01 2009-12-31   30          X
7  2243  14543 2010-01-01 2010-01-31   31          X

私はこれを一度だけ行う必要があるので、どのツールがこれを行うことができるかについてはかなり不可知論者です。

追加のしわは、テーブルの長さが約150,000行であるということです。これは、ほとんどの標準ではそれほど大きくはありませんが、Rでのループソリューションを困難にするのに十分な大きさです。Rでzoo、xts、tempdisaggパッケージを使用して調査しました。各請求書を分割し、既存の請求書内に毎月1行を作成し、tapply()を使用してアカウントごとに要約する非常に醜いループを書き始めました。と数ヶ月、しかし正直なところ、それを効率的に行う方法を見ることができませんでした。

MySQLでは、これを試しました。

ビューv3をselect1n union all select 1 union allselect1として作成または置換します。
ビューvをv3a、v3 b union allselect1からselect1nとして作成または置換します。
@n=0に設定します。
カレンダーが存在する場合はテーブルを削除します。テーブルカレンダーを作成します(dt日付主キー);
カレンダーに挿入
selectcast( '2008-1-1' + interval @ n:= @ n + 1 day as date)as dt from va、vb、vc、vd、ve、v;

select acct、amount、begin、end、billAmtPerDay、sum(billAmtPerDay)、MonthAmt、count()Days、sum(billAmtPerDay)/ count()AverageAmtPerDay、year(dt)、month(dt)FROM(select *、amount / days billAmtPerDay from bills b internal join calendar c on dt between begin and end and begin <> dt)x group by acct、amount、begin、end、billAmtPerDay、year(dt)、month(dt);

しかし、私にはわからない理由で、私のサーバーはこのテーブルが気に入らず、さまざまな計算をステージングしても、内部結合でハングアップします。一時的なメモリ制限があるかどうかを調査しています。

ありがとう!

4

2 に答える 2

9

これが使用の開始data.tableです:

billdata <- read.table(text=" acct amount begin end days
1 2242 11349 2009-10-06 2009-11-04 29
2 2242 12252 2009-11-04 2009-12-04 30
3 2242 21774 2009-12-04 2010-01-08 35
4 2242 18293 2010-01-08 2010-02-05 28
5 2243 27217 2009-10-06 2009-11-04 29
6 2243 117 2009-11-04 2009-12-04 30
7 2243 14543 2009-12-04 2010-01-08 35", sep=" ", header=TRUE, row.names=1)

require(data.table)
DT = as.data.table(billdata)

まず、列の種類とbegin日付を変更endします。data.frameとは異なり、これはデータセット全体をコピーしません。

DT[,begin:=as.Date(begin)]
DT[,end:=as.Date(end)]

次に、期間を見つけ、毎日の一般的な請求書を見つけて、集計します。

alldays = DT[,seq(min(begin),max(end),by="day")]

setkey(DT, acct, begin)

DT[CJ(unique(acct),alldays),
   mean(amount/days,na.rm=TRUE),
   by=list(acct,month=format(begin,"%Y-%m")), roll=TRUE]

    acct   month        V1
 1: 2242 2009-10 391.34483
 2: 2242 2009-11 406.69448
 3: 2242 2009-12 601.43226
 4: 2242 2010-01 646.27465
 5: 2242 2010-02 653.32143
 6: 2243 2009-10 938.51724
 7: 2243 2009-11  97.36172
 8: 2243 2009-12 375.68065
 9: 2243 2010-01 415.51429
10: 2243 2010-02 415.51429

SQLでは、一般的な結合ロジックが非常に面倒で、速度が遅いことがわかると思います。

それは完全に正しくないので、私はそれがヒントだと言います。アカウント2243はアカウント2242とは異なり、2010-02に拡張されないため、行10が繰り返されていることに注意してください。これを終了するにはrbind、各アカウントの最後の行で、のrolltolast代わりにを使用できますrollalldaysまたは、すべてのアカウントではなく、アカウントで作成することもできます。

上記で速度が許容できるかどうかを確認してください。そこから進むことができます。

1.8.3で修正された1.8.2のバグが発生する可能性があります。私はv1.8.3を使用しています。

欠落しているグループを含む結合とgroupbyを組み合わせる場合の「内部」エラーメッセージが修正されました、#2162。例:X [Y、.N、by = NonJoinColumn]ここで、YにはXと一致しない行がいくつか含まれています。このバグにより、セグメンテーション違反が発生する可能性もあります。

お知らせください。回避するか、R-Forgeから1.8.3にアップグレードできます。

ところで、いい例のデータ。それは答えるのをより速くしました。


上記でほのめかされた完全な答えはここにあります。のいくつかの機能を組み合わせているので、私が認めなければならないのは少し注意が必要ですdata.table。これは1.8.2で機能するはずですが、私は1.8.3でしかテストしていません。

DT[ setkey(DT[,seq(begin[1],last(end),by="day"),by=acct]),
    mean(amount/days,na.rm=TRUE),
    by=list(acct,month=format(begin,"%Y-%m")), roll=TRUE]

   acct   month        V1
1: 2242 2009-10 391.34483
2: 2242 2009-11 406.69448
3: 2242 2009-12 601.43226
4: 2242 2010-01 646.27465
5: 2242 2010-02 653.32143
6: 2243 2009-10 938.51724
7: 2243 2009-11  97.36172
8: 2243 2009-12 375.68065
9: 2243 2010-01 415.51429
于 2012-10-02T17:38:06.363 に答える
3

これを行う1つの方法は次のとおりです。

billdata <- read.table(text=" acct amount begin end days
1 2242 11349 2009-10-06 2009-11-04 29
2 2242 12252 2009-11-04 2009-12-04 30
3 2242 21774 2009-12-04 2010-01-08 35
4 2242 18293 2010-01-08 2010-02-05 28
5 2243 27217 2009-10-06 2009-11-04 29
6 2243 117 2009-11-04 2009-12-04 30
7 2243 14543 2009-12-04 2010-01-08 35", sep=" ", header=TRUE, row.names=1)

#First, declare your columns "begin" and "end" as dates:
strptime(billdata$begin, format="%Y-%m-%d") -> billdata$begin
strptime(billdata$end, format="%Y-%m-%d") -> billdata$end

#Then create a column with the amount per day on the billing period:
billdata$avg_on_period<-billdata$amount/billdata$days

#Then split it into days:
temp <- data.frame(acct=c(),month=c(),day=c(), avg=c())
for(i in 1:nrow(billdata)){
    X <- billdata[i,]
    seq(X$begin,X$end,by="day") -> list_day
    rbind(temp, data.frame(acct=rep(X$acct,length(list_day)), 
        month=format(list_day, "%Y-%m"), day=format(list_day, "%d"), 
        avg=rep(X$avg_on_period, length(list_day)))) -> temp
    }

# And finally merge the different days of the months together:
output<-aggregate(temp$avg, by=list(temp$month,temp$acct), FUN=mean)

colnames(output) <- c("Month","Account","Average per day")

output
    Month Account Average per day
1 2009-10    2242       391.34483
2 2009-11    2242       406.69448
3 2009-12    2242       595.40000
4 2010-01    2242       645.51964
5 2010-02    2242       653.32143
6 2009-10    2243       938.51724
7 2009-11    2243        97.36172
8 2009-12    2243       364.06250
9 2010-01    2243       415.51429
于 2012-09-24T08:11:20.063 に答える