2012-09-24 7 views
6

エネルギー使用に季節的な影響を与えるためには、私が使用しているエネルギー使用情報を請求データベースから毎月の温度に合わせる必要があります。不規則な時系列を定期的な月別平均値に分割する - R

私はさまざまな長さと開始日と終了日の請求書を持つ請求データセットを使用しており、毎月の各アカウントの月間平均を取得したいと考えています。例えば、私は次のような特徴を持っている課金データベースを持っている:

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 

私は、各月以内に一日あたりの平均量を得るために(アカウントごと)これらのやや不規則時系列を強制する方法を見つけ出すしたいと思いますそれは、各法案の中にまたがるようにされています

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で動物園、xts、tempdisaggパッケージを使用して調査しました。それぞれの請求書を分割し、既存の請求書内の各月ごとに1行を作成し、次にacctsで要約するためにtapply()正直なところ、それを効率的に行う方法は見当たりませんでした。 MySQLでは

、私はこれを試してみた:

選択1からn組合としてビューv3のすべてを作成したり、交換するすべての1つの組合を選択1を選択します。
ビューの作成または置換v as select 1 n from v3 a、v3 bユニオンすべてselect 1;
セット@n = 0;
ドロップテーブルが存在する場合はカレンダーです。 テーブルカレンダーを作成する(dt日付の主キー)。
カレンダーに挿入
dt をv a、v b、v c、v d、v e、vから選択キャスト( '2008-1-1' +間隔@n:= n n + 1日)

選択ACCT、量、開始、終了、billAmtPerDay、合計(billAmtPerDay)、MonthAmt、 数()日数、合計(billAmtPerDay)/数()AverageAmtPerDay、年(DT)、月(DT) FROM(選択*、金額/日billAmtPerDay 請求書からb 開始と終了の間のdtの内部結合カレンダーc <> dt)x acct、amount、begin、end、billAmtPerDay、year(dt)、month (dt);

私は理解できませんが、私のサーバーはこのテーブルが気に入らず、別の計算を行っていても内部結合でハングアップします。私はそれに一時的なメモリの制限があるかどうか調べています。

ありがとうございます!ここで

+1

請求月間は実際の月と一致するのか、または「新しい期間が始まると毎月のXがある」タイプの状況ですか? –

+0

請求期間は不規則であるため、ほとんどの請求書は平均30 +/2日ですが、一部の請求書では90日以上の長さです。 – bikeclub

+1

次に、ちょうど日付を指定して請求期間を計算する方法が必要なので、適切なグループ化ができます。 –

答えて

8

ここ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とは異なり、これはデータセット全体をコピーしません。

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

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では非常に扱いにくいロジックが一般的であると感じています。

私はそれがヒントであると言うのは、それはかなり正しいとは言えないからです。通知行10は、アカウント2243がアカウント2242とは異なり2010-02に引き伸ばされないため繰り返されます。それを解消するには、rollの代わりにrolltolastを最後の行のrbindとすることができます。すべてのアカウントではなく、アカウント別にalldaysを作成することもできます。

上記の速度が許容できるかどうかを確認してください。

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

不足しているグループとグループを含む結合を結合するときの "内部"エラーメッセージは、 が#2162固定です。例: X [Y、.N、by = NonJoinColumn] ここで、YにはXと一致しない行がいくつか含まれています。このバグはseg という結果にもなります。

私に教えてください。私たちは、回避するか、R-Forgeから1.8.3にアップグレードすることができます。

Btw、いい例のデータです。それは答えに素早くなりました。


ここでは、上記の完全な答えを示します。それは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 
+0

こんにちはMatthew、以前は返答しませんでした - 両方の方法を実行しましたが、data.tableソリューション*ははるかに高速ですが、回答が異なるので、両方のコードをチェックしています。 – bikeclub

+1

@ D.Hsu一見すると、例のデータはあいまいであると考えられるので、他の答えは各請求書の最終日を二重にカウントするかもしれないと私は思う。私の答えは[開始、終了]ではなく[開始、終了]を使用します。 –

+0

Matt、私はそれをチェックし、あなたのコードはうまくいきます。私がチェックアウトするのに数日かかった理由は、私が実際に問題で提起した計算とは少し異なる計算を考えているということでした。それにもかかわらず、data.table関数は非常に高速で、私の(最終的な)目的のために変更するのが比較的簡単でした。私の質問に答えるだけでなく、パッケージを開発してくれてありがとう。 – bikeclub

3

はそれを行うための一つの方法である:

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

このクイック返信をありがとう。私はコードを試してみると応答が遅れました。しかし、私はこれまで、これを比較的大きなデータセットに適用したいと思います.150,000行で、これは5〜6時間でコードの約10%(非常に高速なサーバー上で)でした。私はこれがおそらくSQLを使って解決されると思う。 – bikeclub

+0

実際に、データセットが150,000行の場合、中間の 'temp'データセットは数百万行になります。おそらく 'データを使う良い解決法があります。私はここで助けることができないので、私はそれを使用したことはありません。 – plannapus

+0

plannapus、@ D.Hsu、はい、それは 'data.table'にとって大きな疑問と理想です。後で回答を追加します。 –

関連する問題