4

我有一个非常大(近 6m 行)的数据框,称为 DF,具有以下结构:

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

RelMonth定义为自与 相关的特定静态事件以来的月数CodeContract

此数据已按CodeContract和按 排序RelMonth。数据框当前保持连续RelMonth;即对于任何给定CodeContract的所有临时RelMonth填充,例如对于给定的填充,CodeContract如果我有 MinRelMonth=5和 Max RelMonth=12,那么数据框将包括RelMonths 5:12.

我想计算另一个名为的列Mths_since_last_Pmt,该列将计算给定CodeContractRelMonths自给定 aCodeContract以来的数量AmtPmt > 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循环的工作解决方案,但它只能处理大约 5,000 行/秒。

我正在寻找一种方法来向量化这个计算,甚至可能不先对数据进行排序,或者不中断RelMonths.

我尝试开发的所有矢量化解决方案,通常使用ddply那个 call seq_along,最终都会耗尽我的 RAM (24GB)。我正在寻找一种可以在 2GB 内存使用下运行的解决方案。也许是自定义函数形式的解决方案?

知道如何进行这项工作吗?

更新@Roland

@罗兰

我发现了一个稍微不同的数据集,它会导致下面的代码输出错误。调整后的输入是:

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 回答