4

次の構造を持つ DF と呼ばれる非常に大きな (約 6m 行) データフレームがあります。

CodeContract    RelMonth    AmtPmt
A0001           10          0.00
A0001           11          15.00
A0002           12          4.55
A0003           4           0.00
...             ...         ...

RelMonthに関連付けられた特定の静的イベントからの月数として定義されCodeContractます。

CodeContractこのデータは既におよび でソートされていRelMonthます。データ フレームは現在連続していRelMonthます。つまり、CodeContractMinと MaxがRelMonthあるCodeContract場合、データ フレームには が含まれます。RelMonth=5RelMonth=12RelMonths 5:12

特定の aが a を持ってから何回経ったかMths_since_last_Pmtをカウントするという別の列を計算したいと思います。CodeContractRelMonthsCodeContractAmtPmt > Amt_threshold

このように動作します(仮定Amt_threshold=5

CodeContract    RelMonth    AmtPmt  Mths_since_last_Pmt
A0001           1           0.00    1
A0001           2           3.00    2
A0001           3           0.00    3
A0001           4           10.00   0
A0001           5           0.00    1
A0002           1           10.00   0
A0002           2           12.00   0
A0002           3           0.00    1
A0002           4           0.00    2

現在、ループを使用する実用的なソリューションがありForますが、1 秒あたり約 5,000 行しか処理できません。

この計算をベクトル化する方法を探しています。最初にデータを並べ替えたり、途切れさせたりする必要はありませんRelMonths

私が開発しようとしたすべてのベクトル化されたソリューションは、通常ddplyその callseq_alongで、最終的に RAM (24GB) を使い果たします。2GB 未満の RAM 使用量で実行できるソリューションを探しています。たぶん、カスタム関数の形での解決策でしょうか?

これを機能させる方法はありますか?

更新@ローランド

@ローランド

以下のコードで誤った出力をもたらす、わずかに異なるデータセットを見つけました。微調整された入力は次のとおりです。

DF <- read.table(text="CodeContract    RelMonth    AmtPmt  Mths_since_last_Pmt
A0001           1           0.00    1
A0001           2           3.00    2
A0001           3           0.00    3
A0001           4           10.00   0
A0001           5           0.00    1
A0002           1           1.00   0
A0002           2           14.00   0
A0002           3           14.00    1
A0002           4           14.00    2",header=TRUE)

対応する出力は次のとおりです。

CodeContract RelMonth AmtPmt Mths_since_last_Pmt Mths_since_last_Pmt2
1:        A0001        1      0                   1                    1
2:        A0001        2      3                   2                    2
3:        A0001        3      0                   3                    3
4:        A0001        4     10                   0                    0
5:        A0001        5      0                   1                    1
6:        A0002        1      1                   0                    1
7:        A0002        2     14                   0                    0
8:        A0002        3     14                   1                   -1
9:        A0002        4     14                   2                   -2

最後の行の負の数-1-2inは正しくありません。両方ともしきい値を超えているMths_since_last_Pmt2はずです。0最初の項目がサブグループ (ここではCodeContract変更による) である場合、アルゴリズムは失敗するように思われますが、しきい値を下回っているだけで十分です。

これを機能させるために適用できる微調整はありますか?

4

2 に答える 2

5

これを試して:

DF <- read.table(text="CodeContract    RelMonth    AmtPmt  Mths_since_last_Pmt
A0001           1           0.00    1
A0001           2           3.00    2
A0001           3           0.00    3
A0001           4           10.00   0
A0001           5           0.00    1
A0002           1           10.00   0
A0002           2           12.00   0
A0002           3           0.00    1
A0002           4           0.00    2",header=TRUE)

library(data.table)

DT <- data.table(DF,key=c("CodeContract","RelMonth"))

trsh <- 5
DT[,Mths_since_last_Pmt2 := 
       cumsum(AmtPmt<=trsh)-cumsum(cumsum(AmtPmt<=trsh)*(AmtPmt>trsh)),
            by=CodeContract]

#    CodeContract RelMonth AmtPmt Mths_since_last_Pmt Mths_since_last_Pmt2
# 1:        A0001        1      0                   1                    1
# 2:        A0001        2      3                   2                    2
# 3:        A0001        3      0                   3                    3
# 4:        A0001        4     10                   0                    0
# 5:        A0001        5      0                   1                    1
# 6:        A0002        1     10                   0                    0
# 7:        A0002        2     12                   0                    0
# 8:        A0002        3      0                   1                    1
# 9:        A0002        4      0                   2                    2

うまくいけば、参照による data.table の割り当てにより、RAM の制限を超えないようにすることができます。

于 2013-04-05T17:21:32.940 に答える
1

さて、私はSOで同様の問題を抱えている人を見つけることができ、私の問題への答えを適応させることができました. @sven-hohensteinへの称賛

答えは次のようになります。

require(data.table)
DF<-as.data.table(DF)

最初に、しきい値を下回る1場合に返されるしきい値テスト ベクトルを作成しました。AmtPmt

DF$trsh_test[DF$AmtPmt<trsh]<-1
DF$trsh_test[is.na(DF$trsh_test)]<-0

第二に、ave機能とともにseq_along

DF[,Mths_since_last_Pmt2 := 
        trsh_test * ave(trsh_test, c(0L, cumsum(diff(trsh_test) != 0)), 
        FUN = seq_along) ,
        by=CodeContract]

次の出力が得られますが、これは正しいものです。

CodeContract RelMonth AmtPmt Mths_since_last_Pmt trsh_test Mths_since_last_Pmt2
A0001        1      0                   1         1                    1
A0001        2      3                   2         1                    2
A0001        3      0                   3         1                    3
A0001        4     10                   0         0                    0
A0001        5      0                   1         1                    1
A0002        1      1                   0         1                    1
A0002        2     14                   0         0                    0
A0002        3     14                   1         0                    0
A0002        4     14                   2         0                    0
于 2014-06-24T18:17:08.180 に答える