Rのマトリックスよりもデータフレームで「一意」を実行するのはなぜですか?

StackOverflow https://stackoverflow.com/questions/7809570

質問

私は、表記の利便性を除いて、データフレームがマトリックスよりも利点がないと信じ始めています。しかし、私は走るときにこの奇妙さに気づきました unique マトリックスとデータフレームでは、データフレームでより速く実行されるようです。

a   = matrix(sample(2,10^6,replace = TRUE), ncol = 10)
b   = as.data.frame(a)

system.time({
    u1 = unique(a)
})
 user  system elapsed
1.840   0.000   1.846


system.time({
    u2 = unique(b)
})
 user  system elapsed
0.380   0.000   0.379

行の数が増えるにつれて、タイミングの結果はさらに大幅に分岐します。したがって、この質問には2つの部分があります。

  1. なぜこれがマトリックスの方が遅いのですか?データフレームに変換する方が速く、実行してください unique, 、そして変換します。

  2. 包むだけではない理由はありますか uniquemyUnique, 、パート#1の変換はどれですか?


注1.マトリックスがアトミックであることを考えると、 unique マトリックスの方が遅くなるのではなく、より速くする必要があります。固定サイズの連続的なメモリブロックを繰り返すことができることは、一般に、リンクされたリストの個別のブロックを実行するよりも高速でなければなりません(それがデータフレームの実装方法だと思います...)。

注2.のパフォーマンスによって示されているように data.table, 、 ランニング unique データフレームまたはマトリックスは比較的悪い考えです - マシュー・ダウルによる答えと相対的なタイミングのコメントを参照してください。私は多くのオブジェクトをデータテーブルに移行しましたが、このパフォーマンスはそうするもう1つの理由です。したがって、ユーザーはデータテーブルを採用するのに適切に提供されるべきですが、教育的 /コミュニティの理由から どうして マトリックスオブジェクトでこれには時間がかかりますか。以下のアドレスの回答 どこ 時間はありますか、そして 他には より良いパフォーマンスを得ることができますか(つまり、データテーブル)。の答え どうして 近くにあります - コードは経由で見つけることができます unique.data.frameunique.matrix. 。 :)それが何をしているのか、そしてなぜすべてが欠けているのかについての英語の説明。

役に立ちましたか?

解決

  1. この実装では、 unique.matrix と同じです unique.array

    > identical(unique.array, unique.matrix)

    [1] TRUE

  2. unique.array 余分な寸法を「崩壊」するために追加の処理が必要な多次元配列を処理する必要があります(それらの追加の呼び出し paste())2次元の場合は必要ありません。コードの重要なセクションは次のとおりです。

    collapse <- (ndim > 1L) && (prod(dx[-MARGIN]) > 1L)

    temp <- if (collapse) apply(x, MARGIN, function(x) paste(x, collapse = "\r"))

  3. unique.data.frame 2Dケースに最適化されています。 unique.matrix ではありません。あなたが提案するように、それは現在の実装ではないかもしれません。

すべての場合において、複数の次元がある場合、一意性と比較される文字列表現であることに注意してください。浮動小数点数の場合、これは15桁の数字を意味しますので

NROW(unique(a <- matrix(rep(c(1, 1+4e-15), 2), nrow = 2)))

1 その間

NROW(unique(a <- matrix(rep(c(1, 1+5e-15), 2), nrow = 2)))

NROW(unique(a <- matrix(rep(c(1, 1+4e-15), 1), nrow = 2)))

両方とも 2. 。あなたは 承知しました unique あなたが欲しいものは何ですか?

他のヒント

  1. 確かではありませんが、そうだと思います matrix 1つの隣接するベクトルであり、Rは最初に列ベクトルにコピーします( data.frame) なぜなら paste ベクトルのリストが必要です。両方が使用されるため、両方とも遅いことに注意してください paste.

  2. おそらく unique.data.table すでに何倍も速いです。 r-forgeリポジトリからダウンロードしてv1.6.7にアップグレードしてください。 unique あなたは育てました この質問. data.table 使用しません paste やる unique.

a = matrix(sample(2,10^6,replace = TRUE), ncol = 10)
b = as.data.frame(a)
system.time(u1<-unique(a))
   user  system elapsed 
   2.98    0.00    2.99 
system.time(u2<-unique(b))
   user  system elapsed 
   0.99    0.00    0.99 
c = as.data.table(b)
system.time(u3<-unique(c))
   user  system elapsed 
   0.03    0.02    0.05  # 60 times faster than u1, 20 times faster than u2
identical(as.data.table(u2),u3)
[1] TRUE

自分の質問、特にパート1に答えようとする際に、結果を調べることで時間がどこに費やされているかを見ることができます Rprof. 。 5mの要素でこれを再び実行しました。

最初の一意の操作(マトリックス用)の結果は次のとおりです。

> summaryRprof("u1.txt")
$by.self
                     self.time self.pct total.time total.pct
"paste"                   5.70    52.58       5.96     54.98
"apply"                   2.70    24.91      10.68     98.52
"FUN"                     0.86     7.93       6.82     62.92
"lapply"                  0.82     7.56       1.00      9.23
"list"                    0.30     2.77       0.30      2.77
"!"                       0.14     1.29       0.14      1.29
"c"                       0.10     0.92       0.10      0.92
"unlist"                  0.08     0.74       1.08      9.96
"aperm.default"           0.06     0.55       0.06      0.55
"is.null"                 0.06     0.55       0.06      0.55
"duplicated.default"      0.02     0.18       0.02      0.18

$by.total
                     total.time total.pct self.time self.pct
"unique"                  10.84    100.00      0.00     0.00
"unique.matrix"           10.84    100.00      0.00     0.00
"apply"                   10.68     98.52      2.70    24.91
"FUN"                      6.82     62.92      0.86     7.93
"paste"                    5.96     54.98      5.70    52.58
"unlist"                   1.08      9.96      0.08     0.74
"lapply"                   1.00      9.23      0.82     7.56
"list"                     0.30      2.77      0.30     2.77
"!"                        0.14      1.29      0.14     1.29
"do.call"                  0.14      1.29      0.00     0.00
"c"                        0.10      0.92      0.10     0.92
"aperm.default"            0.06      0.55      0.06     0.55
"is.null"                  0.06      0.55      0.06     0.55
"aperm"                    0.06      0.55      0.00     0.00
"duplicated.default"       0.02      0.18      0.02     0.18

$sample.interval
[1] 0.02

$sampling.time
[1] 10.84

データフレームの場合:

> summaryRprof("u2.txt")
$by.self
                     self.time self.pct total.time total.pct
"paste"                   1.72    94.51       1.72     94.51
"[.data.frame"            0.06     3.30       1.82    100.00
"duplicated.default"      0.04     2.20       0.04      2.20

$by.total
                        total.time total.pct self.time self.pct
"[.data.frame"                1.82    100.00      0.06     3.30
"["                           1.82    100.00      0.00     0.00
"unique"                      1.82    100.00      0.00     0.00
"unique.data.frame"           1.82    100.00      0.00     0.00
"duplicated"                  1.76     96.70      0.00     0.00
"duplicated.data.frame"       1.76     96.70      0.00     0.00
"paste"                       1.72     94.51      1.72    94.51
"do.call"                     1.72     94.51      0.00     0.00
"duplicated.default"          0.04      2.20      0.04     2.20

$sample.interval
[1] 0.02

$sampling.time
[1] 1.82

私たちが気づくのは、マトリックスバージョンが多くの時間を費やしていることです apply, paste, 、 と lapply. 。対照的に、データフレームバージョンは単純に実行されます duplicated.data.frame そして、ほとんどの時間は費やされています paste, 、おそらく結果の集計です。

これは説明していますが どこ 時が来ました、それは説明しません どうして これらには、実装が異なることも、あるオブジェクトタイプから別のオブジェクトタイプに単純に変更する効果もありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top