如何通过替换“a”来提高大型数据集的性能;for loop";及;如有其他",;条款

如何通过替换“a”来提高大型数据集的性能;for loop";及;如有其他",;条款,r,performance,if-statement,for-loop,apply,R,Performance,If Statement,For Loop,Apply,亲爱的社区: 我安静地坐在一个特定的数据集上,这个数据集相当大(nrow=约5亿)。经过一系列的数据处理,数据集基本上包括以下重要列:“ParticleId”、“flag”、“Volume”和“reduce” ParticleId是唯一的,它表示一个在时间和空间中移动的粒子 该标志指示粒子是否在特定区域内(是/否) 每个ParticleId都有一个先前的体积(注入时),如果粒子位于该特定区域的内部或外部,则该体积取决于时间 如果粒子位于特定区域内,则必须按相应的减少值减少以前的体积 我编写了

亲爱的社区:

我安静地坐在一个特定的数据集上,这个数据集相当大(nrow=约5亿)。经过一系列的数据处理,数据集基本上包括以下重要列:“ParticleId”、“flag”、“Volume”和“reduce”

  • ParticleId是唯一的,它表示一个在时间和空间中移动的粒子
  • 该标志指示粒子是否在特定区域内(是/否)
  • 每个ParticleId都有一个先前的体积(注入时),如果粒子位于该特定区域的内部或外部,则该体积取决于时间
  • 如果粒子位于特定区域内,则必须按相应的减少值减少以前的体积
我编写了一个带有2个if-else子句的for循环,以减少每行的容量。该循环经过测试,可以完美地用于测试目的,最多可用于20k行的子集。不幸的是,当应用于孔数据集(500mio.rows)时,性能呈指数级下降。我尝试了几种矢量化的方法,但似乎遗漏了一些东西。我真的很感谢你的帮助和对这个具体问题的矢量化的想法

请在下面查找for循环和测试数据集:

dataset <- data.frame(1:20)
dataset$ParticleId        <- c(1,1,1,1,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4)
dataset$flag      <- c(T,T,T,F,T,T,F,F,T,T,T,T,T,T,F,F,F,F,T,T)
dataset$Volume    <- 0.01
dataset$reduction <- c(1.21e-03,1.21e-04,1.21e-03,1.21e-06,1.21e-03,1.21e-03,1.21e-04,1.21e-03,1.21e-06,1.21e-03,1.21e-03,1.21e-04,1.21e-03,1.21e-06,1.21e-03,1.21e-03,1.21e-04,1.21e-03,1.21e-06,1.21e-03)

for(i in 2:nrow(dataset)){
  if(dataset[i,]$flag == TRUE & dataset[i,]$ParticleId == dataset[i-1,]$ParticleId){
    dataset[i,]$Volume <- dataset[i-1,]$Volume - dataset[i-1,]$reduction
  }else{
    if(dataset[i,]$flag == FALSE & dataset[i,]$ParticleId == dataset[i-1,]$ParticleId){
      dataset[i,]$Volume <- dataset[i-1,]$Volume
    }else{
      dataset[i,]$Volume <- dataset[i,]$Volume
    }
   }
 }

dataset这将生成所需的输出,并且应该比使用
for
-循环和
if.的初始方法快很多。。其他..
语句:

library(dplyr)
dataset %>% 
  group_by(ParticleId) %>% 
  mutate(Volume = Volume[1L] - cumsum(lag(reduction, default = 0L)*flag))

#Source: local data frame [20 x 5]
#Groups: ParticleId
#
#   X1.20 ParticleId  flag     Volume reduction
#1      1          1  TRUE 0.01000000  1.21e-03
#2      2          1  TRUE 0.00879000  1.21e-04
#3      3          1  TRUE 0.00866900  1.21e-03
#4      4          1 FALSE 0.00866900  1.21e-06
#5      5          2  TRUE 0.01000000  1.21e-03
#6      6          2  TRUE 0.00879000  1.21e-03
#7      7          2 FALSE 0.00879000  1.21e-04
#8      8          2 FALSE 0.00879000  1.21e-03
#9      9          2  TRUE 0.00758000  1.21e-06
#10    10          3  TRUE 0.01000000  1.21e-03
#11    11          3  TRUE 0.00879000  1.21e-03
#12    12          4  TRUE 0.01000000  1.21e-04
#13    13          4  TRUE 0.00987900  1.21e-03
#14    14          4  TRUE 0.00866900  1.21e-06
#15    15          4 FALSE 0.00866900  1.21e-03
#16    16          4 FALSE 0.00866900  1.21e-03
#17    17          4 FALSE 0.00866900  1.21e-04
#18    18          4 FALSE 0.00866900  1.21e-03
#19    19          4  TRUE 0.00745900  1.21e-06
#20    20          4  TRUE 0.00745779  1.21e-03
它的作用是:

  • 以数据“数据集”为例
  • 按ParticleId对数据进行分组(然后对每组执行以下操作)
  • mutate
    用于修改/添加数据列。在本例中,我们修改现有列“Volume”。我们取每组体积的第一个元素(
    Volume[1L]
    ),并从该值中减去
    reduction*flag
    的累积和。因为我们将
    reduce
    标志
    相乘,这是一个逻辑列,所以只要
    标志
    ,reduce就乘以1,只要
    标志
    ,reduce就乘以0。这意味着,如果
    flag
    FALSE
    ,我们将从Volume列中减去0(无)(即保持原样)。此外,我们使用
    lag(Volume,default=0)
    ,因为我们希望在每一行中减去前一行(lag)中出现的
    减少值。
    default=0
    确保,如果一个组中没有前一行,即我们在一个组的第一行上操作,则前一个减少值假定为0,因此,我们不会从第一行体积值中减去任何东西
  • 如果您想知道为什么我在数字后面使用L(如在
    default=0L
    ):它用于表示
    整数
    ——这些值使用更少的内存,因此可以帮助代码加快一点速度,因为您处理的数据量相当大

我尝试在data.table中使用相同的代码(可能更快一点):

我认为在最新版本的data.table(1.9.5)中,您可以使用
shift
创建滞后减少


该方法与这里的dplyr解决方案基本相同。但在开始之前,我们使用
setDT()
将data.frame转换为
data.table
对象,并使用
setkey()
设置键。除数据外,其余数据非常相似。表通过引用更新数据(使用
:=
),而不是
滞后(…,默认值=0)
我们使用
c(0,head(reduce,-1))

真是天才。谢谢!我用我的40k子集尝试了你的代码,结果在1-2秒内完成了。一旦我以同样的方式操作了孔数据集,我将尝试使用改进的孔数据集(data.table)。我真的很感激,尽管我能大致理解您是如何使用这些函数的。你能推荐一些文献来学习这个复杂的组合吗?我会在我的答案中添加一个简短的解释。通常,您可以通过阅读CRAN(和)上的文档来了解这些包及其功能。对于dplyr,您还可以查看和。@Herbert对于
数据表
,我们正在创建更详细的渐晕图。新的应该让你开始。其他小插曲的链接可用。新的小插曲也将在那里更新。HTH.@docendo discimus感谢您提供的额外信息-这些信息帮助很大。阿伦:谢谢你的评论。我来看看推荐的文献。我希望这些答案也能帮助其他人,因为我无法通过密集的网络搜索找到类似的解决方案。
library(data.table)
setkey(setDT(dataset), ParticleId)[,
      Volume:=Volume[1L]-cumsum(c(0L, head(reduction, -1L))*flag), ParticleId]