R 因为循环计算占用了很多时间

R 因为循环计算占用了很多时间,r,for-loop,R,For Loop,关于下面的问题,前面提出的问题,现在解释精确的计算以改进for循环计算。 这只是样本数据,我有大约200万个数据。请帮助我更快地执行此计算 最终输入数据帧: Item LC Fiscal.Week SS Freq A MW92 2019-W24 20 1 A OY01 2019-W24 10 0 A RM11 2019-W24 5 1 B W

关于下面的问题,前面提出的问题,现在解释精确的计算以改进for循环计算。

这只是样本数据,我有大约200万个数据。请帮助我更快地执行此计算

最终输入数据帧:

Item   LC  Fiscal.Week   SS   Freq    
 A    MW92   2019-W24    20    1           
 A    OY01   2019-W24    10    0       
 A    RM11   2019-W24    5     1       
 B    WK14   2019-W24    112   0       
 B    RS11   2019-W24    30    1       
Item   LC     ToLC
 A    MW92    OY01
 A    OY01    RM11
 B    WK14    RS11
lctolc输入数据帧:

Item   LC  Fiscal.Week   SS   Freq    
 A    MW92   2019-W24    20    1           
 A    OY01   2019-W24    10    0       
 A    RM11   2019-W24    5     1       
 B    WK14   2019-W24    112   0       
 B    RS11   2019-W24    30    1       
Item   LC     ToLC
 A    MW92    OY01
 A    OY01    RM11
 B    WK14    RS11
最终输出数据帧

Item   LC  Fiscal.Week   SS   Freq    SSNew
 A    MW92   2019-W24    20    1        0    
 A    OY01   2019-W24    10    0        0
 A    RM11   2019-W24    5     1        0
 B    WK14   2019-W24    112   0        112
 B    RS11   2019-W24    30    1        0
说明:

首先,我们需要在最终数据帧中找到唯一的项,以便代码逐项运行

对于每个项目,代码应按照lctolc数据框中提到的顺序运行,如项目A,MW92到OY02到RM11,因此首先计算将发生在MW92,然后是OY01,然后是RM11

对于每个项目LC对,它应检入最终数据帧

if we have `Freq == 1` then allocate `SSNew = 0`   else
            `SSNew = SS`
现在,如果SSNew==0,则对于该项目的剩余LCs,即OY01和RM11,so应自动将其SSNew设置为0,而不管其频率值是否为1

然后将开始对项目B进行相同的计算

代码:

结果:

  Item  LC       SS  Freq  rank min_row first_0 SSNew
  <chr> <chr> <dbl> <dbl> <int>   <int>   <int> <dbl>
1 A     MW92     20     1     1       2       2    20
2 A     OY01     10     0     2       2       2     0
3 A     RM11      5     1     3       2       2     0
4 A     LO99     99     2    NA       2       2    99
5 B     WK14    112     0     1       1       1     0
6 B     RS11     30     1     2       1       1     0

这个基本R解决方案遵循lctolc表,但我不知道它是否更快

ssNew <- function(DF, LC2LC){
  f <- function(df1, lc2lc){
    inx <- which(df1[['LC']] %in% unique(unlist(lc2lc)))
    for(i in inx){
      if(df1$Freq[i] == 1) break
      df1$SSnew[i] <- df1$SS[i]
    }
    df1
  }
  g <- function(df1){
    inx <- seq_len(nrow(df1))
    for(i in inx){
      if(df1$Freq[i] == 1) break
      df1$SSnew[i] <- df1$SS[i]
    }
    df1
  }
  DF[['SSnew']] <- 0
  sp1 <- split(DF, DF[['Item']])
  sp2 <- split(LC2LC, LC2LC[['Item']])
  DFItem <- unique(DF[['Item']])
  nms <- intersect(DFItem, LC2LC[['Item']])
  res <- lapply(DFItem, function(i) {
    if(i %in% nms){
      f(sp1[[i]], sp2[[i]])
    }else{
      g(sp1[[i]])
    }
  })
  res <- do.call(rbind, res)
  row.names(res) <- NULL
  res
}

Final_v1 <- ssNew(Final, lctolc)

Final_v1
#  Item   LC Fiscal.Week  SS Freq SSnew
#1    A MW92    2019-W24  20    1     0
#2    A OY01    2019-W24  10    0     0
#3    A RM11    2019-W24   5    1     0
#4    B WK14    2019-W24 112    0   112
#5    B RS11    2019-W24  30    1     0
下面是一个依赖于联接的data.table解决方案

Final <- fread('Item   LC  Fiscal.Week   SS   Freq    
 A    MW92   2019-W24    20    1           
 A    OY01   2019-W24    10    0       
 A    RM11   2019-W24    5     1       
 B    WK14   2019-W24    112   0       
 B    RS11   2019-W24    30    1')

lctolc <- fread(
  'Item   LC     ToLC
 A    MW92    OY01
  A    OY01    RM11
  B    WK14    RS11')
#converting to data.table if reading from xlsx
setDT(Final)
setDT(lctolc)

#initializing
Final[, ToLC := shift(LC, 1, type = 'lead')]
Final[, SSNew := 0L]

# update join
Final[lctolc
      ,on = .(Item, LC, ToLC)
      , SSNew := as.integer(SS)*!Freq] #coerces Freq to logical. If freq is more than 1, it wouldn't work

#condition that if first of each group is 0, then everything is 0.
Final[, SSNew_First := first(SSNew), by = 'Item']
Final[SSNew_First == 0, SSNew := 0]

#clean up data.table by removing unneeded columns
Final[, `:=` (SSNew_First = NULL, ToLC = NULL)]

#print
Final

   Item   LC Fiscal.Week  SS Freq SSNew
1:    A MW92    2019-W24  20    1     0
2:    A OY01    2019-W24  10    0     0
3:    A RM11    2019-W24   5    1     0
4:    B WK14    2019-W24 112    0   112
5:    B RS11    2019-W24  30    1     0

@基于数据帧lctolc中的关系,我们需要继续。对于项目A,我们有关系MW92->OY01->RM11,因此首先我们检查MW92处的Freq值,如果它是Freq=1,我们为MW92分配SSNew=0,也为OY01和RM11分配SSNew=0,也不考虑它们的Freq值。如果MW92处的Freq=0,那么我们为MW92分配SSNew=SS,并在OY01继续检查OY01处的Freq。因此,如果我们设置SSNew=0,那么我们需要根据lctolc数据框架为该项目的所有即将到来的LCs跨SSNew=0进行设置。此外,我收到以下错误:sp2[[I]]中的错误:下标超出bounds@AnshulSaravgiDF和df1只是参数名,在函数中我不使用实名,这些函数处理仅存在于其内部的数据集。至于错误,它是否与其他数据一起发生?对于发布的示例,我没有收到任何错误。是的,当我处理80k数据时,其他数据也出现了错误。因此,我不需要更改参数名称,我应该使用DF和df1吗?@AnshulSaravgi不,不需要更正这些名称,这是函数中的一个错误。我已经纠正了这个错误,我相信它现在可以像预期的那样工作。@AnshulSaravgi注意到,只有当最终版本中的某些项目在lctolc中不存在时,才可能出现错误。你想用这些东西做什么?像这样,函数不处理它们,它们的SSnew将设置为零;此对话已结束。我尝试将Freq==0替换为Freq==1,但似乎不起作用。即使存在Freq==0,它也会使所有内容都为0。请help@M.舒马赫-代码运行超过30分钟,然后也没有输出,并尝试用Freq==1替换Freq==0,但似乎不起作用。即使存在Freq==0,它也会使所有内容都为0。请帮助我们如何对我正在通过xlsxDo setDTFinal加载的数据帧执行此操作,以及对您的其他数据帧执行相同操作。FRAME请参见编辑-在我将fread语句添加到代码中之后。它起作用了吗?