簡體   English   中英

R編程:如何向量化/加速每個過程中需要先前值的for循環

[英]R Programming: How to vectorize/speed up a for loop that need the previous value in each process

我正在做一個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 <4且Distancia> 12且Cura [i- 1]!= 1。 P.Moroso的值必須保留在每個記錄中,直到達到條件時它才更改,這意味着當第一個NUMDCRED出現時,P.Moroso的值將為1,對於下一個記錄也將為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  

目前,Im使用以下簡單的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編程:如何加快耗時2小時的循環以及耗費大量時間的原因

您不需要循環

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

你的意思是這樣的...? (假設您的表名是“ TABLA”)

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

我認為我有一個快速的解決方案,但是我還沒有測試過,所以我真的不知道。 這是我的思考過程:

  1. 您可以先將數據除以NUMDCRED的值,因為每次NUMDCRED更改時P.Moroso的值始終從1開始。 將數據的每個子集放入列表中。

  2. 您現在可以使用lapply將函數應用於列表中的每個數據集。 首先,如果滿足您指定的條件,則創建一個TRUE列,如果未指定條件,則創建一個FALSE列。 然后,您可以對該列進行累加和並將其存儲為P.Moroso列。 我認為那應該是您想要的。

  3. 合並所有數據集。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM