R编程:如何对每个进程中需要先前值的for循环进行向量化/加速

时间:2016-04-07 23:48:00

标签: r loops data.table vectorization

我正在做一个for循环来填充矢量。问题是在每个循环中它需要先前的值来继续进行计算。

我使用的是data.table包,所以它是一个数据表。 R版本64位3.2.3

该表具有f Im执行for循环,但运行需要时间我想知道是否有一种方法可以进行矢量化或使此过程更加快速。我将解释我想要实现的目标。首先我有一个表,因为我需要使用前一个值,因为我需要使用前一个值,因此我无法对操作进行矢量化。

数据表具有以下结构:

NUMDCRED         FDES         Distancia      CURA   NPV
 0001        "2012-01-01"        11            0     1
 0001        "2012-02-01"        12            0     2
 0001        "2012-03-01"        13            1     2
 0001        "2011-01-01"        14            1     3
 0001        "2011-02-01"        15            1     3
 0001        "2011-03-01"        16            1     2 
 0001        "2011-04-01"        10            0     5
 0001        "2011-05-01"        11            0     4
 0001        "2011-06-01"        12            0     6 
 0001        "2011-07-01"        13            1     3
 0001        "2011-08-01"        14            1     2
 0001        "2011-09-01"        15            1     2
 0001        "2011-10-01"        16            1     1
 0001        "2011-11-01"        17            1     3
 0002        "2012-04-01"        11            0     6
 0002        "2012-05-01"        12            0     5
 0002        "2012-06-01"        13            1     4
 0002        "2012-07-01"        14            1     3
 0002        "2012-08-01"        15            1     3
 0002        "2012-09-01"        16            1     3
 0002        "2012-10-01"        10            0     3
 0002        "2012-11-01"        11            0     4
 0002        "2012-12-01"        12            0     4
 0002        "2013-01-01"        13            1     2
 0002        "2013-02-01"        14            1     2
 0002        "2013-03-01"        15            1     3
 0002        "2013-04-01"        16            1     3

通过NUMDCRED和FDES(升序)对表进行排序(POBLACION_MOROSA6)。我需要做的是创建一个名为P.Moroso的其他变量,当第一个不同的NUMDCRED出现时该值设置为1,当条件NPV <1时,该值变为P.Moroso + 1。 4和Distancia&gt; 12和Cura [i-1]!= 1到达。 P.Moroso的值必须保留在每个记录中,直到它达到条件时发生变化,这意味着当第一个NUMDCRED出现时,P.Moroso的值将为1,并且也是下一个记录的值,直到它为止当条件满足时改为P.Moroso + 1(2),然后这个值将保留每个记录等等。

该过程的输出如下:

NUMDCRED         FDES         Distancia      CURA   NPV  P.Moroso
 0001        "2012-01-01"        11            0     1      1
 0001        "2012-02-01"        12            0     2      1
 0001        "2012-03-01"        13            1     2      2
 0001        "2011-01-01"        14            1     3      2
 0001        "2011-02-01"        15            1     3      2
 0001        "2011-03-01"        16            1     2      2
 0001        "2011-04-01"        10            0     5      2
 0001        "2011-05-01"        11            0     4      2
 0001        "2011-06-01"        12            0     6      2
 0001        "2011-07-01"        13            1     3      3
 0001        "2011-08-01"        14            1     2      3
 0001        "2011-09-01"        15            1     2      3
 0001        "2011-10-01"        16            1     1      3
 0001        "2011-11-01"        17            1     3      3
 0002        "2012-04-01"        11            0     6      1
 0002        "2012-05-01"        12            0     5      1
 0002        "2012-06-01"        13            1     4      2
 0002        "2012-07-01"        14            1     3      2
 0002        "2012-08-01"        15            1     3      2
 0002        "2012-09-01"        16            1     3      2
 0002        "2012-10-01"        10            0     3      2
 0002        "2012-11-01"        11            0     4      2
 0002        "2012-12-01"        12            0     4      2
 0002        "2013-01-01"        13            1     2      3
 0002        "2013-02-01"        14            1     2      3
 0002        "2013-03-01"        15            1     3      3
 0002        "2013-04-01"        16            1     3      3  

目前我使用以下简单的foor循环来执行此操作:

PERIODO_MOROSO <- vector(mode = "numeric",length=N3)
isFirstNumdCred_Morosa6 <- (1:N3) %in% FIRST_NUMDCRED_INDEX_P.MOROSA6

for(i in 1:N3){ 

   if(isFirstNumdCred_Morosa6[i]){

      P.MOROSO <- 1
   } else if(POBLACION_MOROSA6[i,NPV] < 4 & POBLACION_MOROSA6[i-1,CURA] ! =1   & POBLACION_MOROSA6[i,DISTANCIA_SALIDA] > 12){

     P.MOROSO <- P.MOROSO + 1
   }

   PERIODO_MOROSO[i] <- P.MOROSO
}

POBLACION_MOROSA6$P.MOROSO <- PERIODO_MOROSO 

变量isFirstNumdCred_Morosa6是一个逻辑向量,指示何时出现第一个不同的Numdcred。我对foor循环的问题是,在处理大数据时它很慢(我的表有900k到200万之间的行。我试过用

ex[,date.seq.3:=ifelse( condition, shift(P.Moroso) +1 , P.Moroso)]

但它没有工作(首先我将所有的分配给第一个不同的NUMDCRED的行)

此外,我尝试使用其他人在我之前发布的这个问题中告诉我的其他方法,但我无法做到。如果有人想看到我遇到类似问题的解决方案,我会把另一个问题的链接。

总而言之,我想知道是否可以矢量化/加速这个过程。 R programming :How to speed up a loop that takes 2 hours and the reasons why it takes a lot

3 个答案:

答案 0 :(得分:3)

你不需要循环

ex <- read.table(header = TRUE, text = 'NUMDCRED         FDES         Distancia      CURA   NPV  P.Moroso
 0001        "2012-01-01"        11            0     1      1
                 0001        "2012-02-01"        12            0     2      1
                 0001        "2012-03-01"        13            1     2      2
                 0001        "2011-01-01"        14            1     3      2
                 0001        "2011-02-01"        15            1     3      2
                 0001        "2011-03-01"        16            1     2      2
                 0001        "2011-04-01"        10            0     5      2
                 0001        "2011-05-01"        11            0     4      2
                 0001        "2011-06-01"        12            0     6      2
                 0001        "2011-07-01"        13            1     3      3
                 0001        "2011-08-01"        14            1     2      3
                 0001        "2011-09-01"        15            1     2      3
                 0001        "2011-10-01"        16            1     1      3
                 0001        "2011-11-01"        17            1     3      3
                 0002        "2012-04-01"        11            0     6      1
                 0002        "2012-05-01"        12            0     5      1
                 0002        "2012-06-01"        13            1     4      2
                 0002        "2012-07-01"        14            1     3      2
                 0002        "2012-08-01"        15            1     3      2
                 0002        "2012-09-01"        16            1     3      2
                 0002        "2012-10-01"        10            0     3      2
                 0002        "2012-11-01"        11            0     4      2
                 0002        "2012-12-01"        12            0     4      2
                 0002        "2013-01-01"        13            1     2      3
                 0002        "2013-02-01"        14            1     2      3
                 0002        "2013-03-01"        15            1     3      3
                 0002        "2013-04-01"        16            1     3      3  ')

在基础中,您可以将逻辑写入函数

f <- function(data)
  cumsum(with(data, Distancia > 12 & NPV <= 4 & c(0, CURA[-length(CURA)]) != 1)) + 1L

并将其应用于数据的子集

ex$P.Moroso2 <- unlist(by(ex, dd$NUMDCRED, f))

identical(ex$P.Moroso, ex$P.Moroso2)
# [1] TRUE

转换为data.table,这看起来像

setDT(ex)[, P.Moroso3 := 
  cumsum(Distancia > 12 & NPV <= 4 & shift(CURA, fill = 0) != 1) + 1L
, by = NUMDCRED]
# or Frank says this works, anyways

答案 1 :(得分:0)

你的意思是这样的......? (假设您的表名是&#34; TABLA&#34;)

P.moroso = c(1)
NUMDCRED = TABLA$NUMDCRED
Cura = TABLA$Cura
NPV = TABLA$NPV
Distancia = TABLA$Distancia   #right now, I just created vectors with the needed columns information

N = length (NUMEDRED)
contador = 1 #the counter set in 1
for (i in 2:N){
    if (NUMDCRED[i-1] != NUMDCRED[i])
       contador = 1  #sets contador in 1 again
    else if ((NVP[i] <4) && (Distancia[i] > 12)&& (Cura[i-1] != 1))
       contador = contador +1  #if the condition happens, increases contador in 1
    P.moroso[i] = contador #append contador in P.moroso vector.
}

现在,你应该有一个带有你想要的数字的P.moroso矢量。最后,你将它附在你的桌子上:

TABLA$P.moroso = P.moroso

答案 2 :(得分:-1)

我想我有一个快速解决方案,但我没有测试过,所以我真的不知道。这是我的思考过程:

  1. 您可以先按NUMDCRED的值拆分数据,因为每次NUMDCRED更改时,P.Moroso的值始终从1开始。将每个数据子集放入一个列表中。

  2. 您现在可以使用lapply将函数应用于列表中的每个数据集。首先,如果满足您指定的条件,则创建一个为TRUE的列;如果未指定条件,则为FALSE。然后,您可以获取此列的累积总和并将其存储为P.Moroso列。我认为那应该是你想要的。

  3. 将所有数据集合并在一起。