11

後で入力するビッグデータフレームを事前に割り当てていました。これは通常、NA次のように行います。

n <- 1e6
a <- data.frame(c1 = 1:n, c2 = NA, c3 = NA)

事前にデータ型を指定しておけば、後でもっと速くなるのではないかと思ったので、テストしました

f1 <- function() {
    a <- data.frame(c1 = 1:n, c2 = NA, c3 = NA)
    a$c2 <- 1:n
    a$c3 <- sample(LETTERS, size= n, replace = TRUE)
}

f2 <- function() {
    b <- data.frame(c1 = 1:n, c2 = numeric(n), c3 = character(n))
    b$c2 <- 1:n
    b$c3 <- sample(LETTERS, size= n, replace = TRUE)
}

> system.time(f1())
   user  system elapsed 
  0.219   0.042   0.260 
> system.time(f2())
   user  system elapsed 
  1.018   0.052   1.072 

だから実際にはずっと遅かった!NAファクター列でも再試行しましたが、差は4xより2xに近くありませんでしたが、なぜこれが遅いのか知りたいので、 'sではなくデータ型で初期化するのが適切かどうか疑問に思います。

-

編集:Flodelは、1:nは整数であり、数値ではないと指摘しました。この修正により、ランタイムはほぼ同じになります。もちろん、データ型を誤って指定して後で変更するのは痛いです!

4

2 に答える 2

13

大きなデータフレームへのデータの割り当てには時間がかかります。(必要に応じて)ベクトルでデータを一度に割り当てる場合は、元の定義でc2列とc3列をまったく割り当てない方がはるかに高速です。例えば:

f3 <- function() {
    c <- data.frame(c1 = 1:n)
    c$c2 <- 1:n
    c$c3 <- sample(LETTERS, size= n, replace = TRUE)
}

print(system.time(f1()))
#   user  system elapsed 
#  0.194   0.023   0.216 
print(system.time(f2()))
#   user  system elapsed 
#  0.336   0.037   0.374 
print(system.time(f3()))
#   user  system elapsed 
#  0.057   0.007   0.063 

これは、事前割り当て時に長さの列nが作成されるためです。例えば

str(data.frame(x=1:2, y = character(2)))
## 'data.frame':    2 obs. of  2 variables:
## $ x: int  1 2
## $ y: Factor w/ 1 level "": 1 1

character列が変換されていることに注意してくださいfactor。これは、設定よりも遅くなりますstringsAsFactors = F

于 2012-09-03T23:48:24.183 に答える
11

@David Robinsonの答えは正しいですが、ここにいくつかのプロファイリングを追加して、一部のthngが予想よりも遅い理由を調査する方法を示します。

ここで行う最善のことは、何が呼び出されているかを確認するためにプロファイリングを行うことです。これにより、一部の呼び出しが他の呼び出しよりも遅い理由を知ることができます。

library(profr)
profr(f1())
## Read 9 items
##                 f level time start  end  leaf source
## 8              f1     1 0.16  0.00 0.16 FALSE   <NA>
## 9      data.frame     2 0.04  0.00 0.04  TRUE   base
## 10            $<-     2 0.02  0.04 0.06 FALSE   base
## 11         sample     2 0.04  0.06 0.10  TRUE   base
## 12            $<-     2 0.06  0.10 0.16 FALSE   base
## 13 $<-.data.frame     3 0.12  0.04 0.16  TRUE   base
profr(f2())
## Read 15 items
##                          f level time start  end  leaf source
## 8                       f2     1 0.28  0.00 0.28 FALSE   <NA>
## 9               data.frame     2 0.12  0.00 0.12  TRUE   base
## 10                       :     2 0.02  0.12 0.14  TRUE   base
## 11                     $<-     2 0.02  0.18 0.20 FALSE   base
## 12                  sample     2 0.02  0.20 0.22  TRUE   base
## 13                     $<-     2 0.06  0.22 0.28 FALSE   base
## 14           as.data.frame     3 0.08  0.04 0.12 FALSE   base
## 15          $<-.data.frame     3 0.10  0.18 0.28  TRUE   base
## 16 as.data.frame.character     4 0.08  0.04 0.12 FALSE   base
## 17                  factor     5 0.08  0.04 0.12 FALSE   base
## 18                  unique     6 0.06  0.04 0.10 FALSE   base
## 19                   match     6 0.02  0.10 0.12  TRUE   base
## 20          unique.default     7 0.06  0.04 0.10  TRUE   base
profr(f3())
## Read 4 items
##                f level time start  end  leaf source
## 8              f3     1 0.06  0.00 0.06 FALSE   <NA>
## 9             $<-     2 0.02  0.00 0.02 FALSE   base
## 10         sample     2 0.04  0.02 0.06  TRUE   base
## 11 $<-.data.frame     3 0.02  0.00 0.02  TRUE   base

コンバージョンや再作成などがたくさんあるので、明らかf2()に遅いです。f1()characterfactorlevels

data.tableメモリを効率的に使用するために、パッケージをお勧めします。これにより、オブジェクトの内部コピーが(可能な限り)回避されます。

library(data.table)
f4 <- function(){
  f <- data.table(c1 = 1:n)
  f[,c2:=1L:n]
  f[,c3:=sample(LETTERS, size= n, replace = TRUE)]
}


system.time(f1())
##  user  system elapsed 
##  0.15    0.02    0.18 
system.time(f2())
## user  system elapsed 
## 0.19    0.00    0.19 
system.time(f3())
## user  system elapsed 
## 0.09    0.00    0.09 
system.time(f4())
## user  system elapsed 
## 0.04    0.00    0.04 

data.tableを使用すると、一度に2つの列を追加できることに注意してください(参照により)

  # Thanks to @Thell for pointing this out.
f[,`:=`(c('c2','c3'), list(1L:n, sample(LETTERS,n, T))), with = F]

EDIT-必要なオブジェクトを返す関数(@Dwinをうまくピックアップ)

n= 1e7
f1 <- function() {
    a <- data.frame(c1 = 1:n, c2 = NA, c3 = NA)
    a$c2 <- 1:n
    a$c3 <- sample(LETTERS, size = n, replace = TRUE)
    a
}

f2 <- function() {
    b <- data.frame(c1 = 1:n, c2 = numeric(n), c3 = character(n))
    b$c2 <- 1:n
    b$c3 <- sample(LETTERS, size = n, replace = TRUE)
    b
}

f3 <- function() {
    c <- data.frame(c1 = 1:n)
    c$c2 <- 1:n
    c$c3 <- sample(LETTERS, size = n, replace = TRUE)
    c
}
f4 <- function() {
    f <- data.table(c1 = 1:n)
    f[, `:=`(c2, 1L:n)]
    f[, `:=`(c3, sample(LETTERS, size = n, replace = TRUE))]

}

system.time(f1())

##    user  system elapsed 
##    1.62    0.34    2.13 

system.time(f2())

##    user  system elapsed 
##    2.14    0.66    2.79 

system.time(f3())

##    user  system elapsed 
##    0.78    0.25    1.03 

system.time(f4())

##    user  system elapsed 
##    0.37    0.08    0.46 


profr(f1())
## Read 105 items
##                        f level time start  end  leaf source
## 8                     f1     1 2.08  0.00 2.08 FALSE   <NA>
## 9             data.frame     2 0.66  0.00 0.66 FALSE   base
## 10                     :     2 0.02  0.66 0.68  TRUE   base
## 11                   $<-     2 0.32  0.84 1.16 FALSE   base
## 12                sample     2 0.40  1.16 1.56  TRUE   base
## 13                   $<-     2 0.32  1.76 2.08 FALSE   base
## 14                     :     3 0.02  0.00 0.02  TRUE   base
## 15         as.data.frame     3 0.04  0.02 0.06 FALSE   base
## 16                unlist     3 0.12  0.54 0.66  TRUE   base
## 17        $<-.data.frame     3 1.24  0.84 2.08  TRUE   base
## 18 as.data.frame.integer     4 0.04  0.02 0.06  TRUE   base
profr(f2())
## Read 145 items
##                          f level time start  end  leaf source
## 8                       f2     1 2.88  0.00 2.88 FALSE   <NA>
## 9               data.frame     2 1.40  0.00 1.40 FALSE   base
## 10                       :     2 0.04  1.40 1.44  TRUE   base
## 11                     $<-     2 0.36  1.64 2.00 FALSE   base
## 12                  sample     2 0.40  2.00 2.40  TRUE   base
## 13                     $<-     2 0.36  2.52 2.88 FALSE   base
## 14                       :     3 0.02  0.00 0.02  TRUE   base
## 15                 numeric     3 0.06  0.02 0.08  TRUE   base
## 16               character     3 0.04  0.08 0.12  TRUE   base
## 17           as.data.frame     3 1.06  0.12 1.18 FALSE   base
## 18                  unlist     3 0.20  1.20 1.40  TRUE   base
## 19          $<-.data.frame     3 1.24  1.64 2.88  TRUE   base
## 20   as.data.frame.integer     4 0.04  0.12 0.16  TRUE   base
## 21   as.data.frame.numeric     4 0.16  0.18 0.34  TRUE   base
## 22 as.data.frame.character     4 0.78  0.40 1.18 FALSE   base
## 23                  factor     5 0.74  0.40 1.14 FALSE   base
## 24    as.data.frame.vector     5 0.04  1.14 1.18  TRUE   base
## 25                  unique     6 0.38  0.40 0.78 FALSE   base
## 26                   match     6 0.32  0.78 1.10  TRUE   base
## 27          unique.default     7 0.38  0.40 0.78  TRUE   base
profr(f3())
## Read 37 items
##                        f level time start  end  leaf source
## 8                     f3     1 0.72  0.00 0.72 FALSE   <NA>
## 9             data.frame     2 0.10  0.00 0.10 FALSE   base
## 10                     :     2 0.02  0.10 0.12  TRUE   base
## 11                   $<-     2 0.08  0.14 0.22 FALSE   base
## 12                sample     2 0.26  0.22 0.48  TRUE   base
## 13                   $<-     2 0.16  0.56 0.72 FALSE   base
## 14                     :     3 0.02  0.00 0.02  TRUE   base
## 15         as.data.frame     3 0.04  0.02 0.06 FALSE   base
## 16                unlist     3 0.02  0.08 0.10  TRUE   base
## 17        $<-.data.frame     3 0.58  0.14 0.72  TRUE   base
## 18 as.data.frame.integer     4 0.04  0.02 0.06  TRUE   base
profr(f4())
## Read 15 items
##               f level time start  end  leaf     source
## 8            f4     1 0.28  0.00 0.28 FALSE       <NA>
## 9    data.table     2 0.02  0.00 0.02 FALSE data.table
## 10            [     2 0.26  0.02 0.28 FALSE       base
## 11            :     3 0.02  0.00 0.02  TRUE       base
## 12 [.data.table     3 0.26  0.02 0.28 FALSE       <NA>
## 13         eval     4 0.26  0.02 0.28 FALSE       base
## 14         eval     5 0.26  0.02 0.28 FALSE       base
## 15            :     6 0.02  0.02 0.04  TRUE       base
## 16       sample     6 0.24  0.04 0.28  TRUE       base
于 2012-09-04T00:22:36.777 に答える