R 因为循环计算占用了很多时间
关于下面的问题,前面提出的问题,现在解释精确的计算以改进for循环计算。 这只是样本数据,我有大约200万个数据。请帮助我更快地执行此计算 最终输入数据帧: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
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语句添加到代码中之后。它起作用了吗?