0

我正在尝试根据另一个数据框中的信息创建一个数据框。

第一个数据帧(base_mar_bop)具有如下数据:

201301|ABC|4
201302|DEF|12

我的愿望是从中创建一个包含 16 行的数据框:

4 times: 201301|ABC|1
12 times: 201302|DEF|1

我编写了一个需要很长时间才能运行的脚本。为了了解最终数据帧有大约 200 万行,源数据帧有大约 10k 行。由于数据的机密性,我无法发布数据帧的源文件。

由于运行这段代码需要很长时间,我决定在 PHP 中执行此操作,它在一分钟内运行并完成了工作,将其写入 txt 文件,然后将 txt 文件导入 R。

我不知道为什么 R 需要这么长时间。是函数的调用吗?它是嵌套的for循环吗?从我的角度来看,那里没有那么多计算密集型的步骤。

# first create an empty dataframe called base_eop that will each subscriber on a row 

identified by CED, RATEPLAN and 1
# where 1 is the count and the sum of 1 should end up with the base
base_eop <-base_mar_bop[1,]

# let's give some logical names to the columns in the df
names(base_eop) <- c('CED','RATEPLAN','BASE')


# define the function that enables us to insert a row at the bottom of the dataframe
insertRow <- function(existingDF, newrow, r) {
  existingDF[seq(r+1,nrow(existingDF)+1),] <- existingDF[seq(r,nrow(existingDF)),]
  existingDF[r,] <- newrow
  existingDF
}


# now loop through the eop base for march, each row contains the ced, rateplan and number of subs
# we need to insert a row for each individual sub
for (i in 1:nrow(base_mar_eop)) {
  # we go through every row in the dataframe
  for (j in 1:base_mar_eop[i,3]) {
    # we insert a row for each CED, rateplan combination and set the base value to 1
    base_eop <- insertRow(base_eop,c(base_mar_eop[i,1:2],1),nrow(base_eop)) 
  }
}

# since the dataframe was created using the first row of base_mar_bop we need to remove this first row
base_eop <- base_eop[-1,]
4

2 回答 2

4

这是一种方法data.table,尽管@BenBolker 的时机已经很棒了。

library(data.table)
DT <- data.table(d2)  ## d2 from @BenBolker's answer
out <- DT[, ID:=1:.N][rep(ID, BASE)][, `:=`(BASE=1, ID=NULL)]
out
#            CED RATEPLAN BASE
#       1:     1        A    1
#       2:     1        A    1
#       3:     1        A    1
#       4:     1        A    1
#       5:     1        A    1
#      ---                    
# 1999996: 10000        Y    1
# 1999997: 10000        Y    1
# 1999998: 10000        Y    1
# 1999999: 10000        Y    1
# 2000000: 10000        Y    1

在这里,我使用复合查询来执行以下操作:

  • 创建一个 ID 变量,它实际上只是 1 到data.table.
  • 用于rep通过相应的 BASE 值重复 ID 变量。
  • 将所有 BASE 值替换为“1”并删除我们之前创建的 ID 变量。

也许有一种更有效的方法可以做到这一点。例如,删除其中一个复合查询应该会使其更快一些。也许是这样的:

out <- DT[rep(1:nrow(DT), BASE)][, BASE:=1]
于 2013-04-25T04:27:40.220 回答
3

我还没有尝试过任何基准测试,但是这种方法(在你的小例子中说明)应该更快

d <- data.frame(x1=c(201301,201302),x2=c("ABC","DEF"),rep=c(4,12))
with(d,data.frame(x1=rep(x1,rep),x2=rep(x2,rep),rep=1))

一个更现实的例子,有时间:

d2 <- data.frame(CED=1:10000,RATEPLAN=rep(LETTERS[1:25],
         length.out=10000),BASE=200) 
nrow(d2) ## 10000
sum(d2$BASE)  ## 2e+06
system.time(d3 <- with(d2,
      data.frame(CED=rep(CED,BASE),RATEPLAN=rep(RATEPLAN,BASE),
              BASE=1)))
##   user  system elapsed 
## 0.244   0.860   1.117 
nrow(d3)  ## 2000000 (== 2e+06)
于 2013-04-24T21:49:32.923 回答