長さが1E8を超える2つの論理ベクトル、x
およびの場合、2x2クロス集計を計算する最も速い方法は何ですか?y
答えはC/C ++で書くことだと思いますが、Rには、珍しいことではないので、この問題についてすでにかなり賢いものがあるのではないかと思います。
コード例、300Mエントリの場合(3E8が大きすぎる場合は、N = 1E8にしてください。合計サイズは2.5GB(2.4GB)未満を選択しました。密度を0.02に設定しました。これは、より面白くするためです(1つは可能です)。それが役立つ場合は、スパースベクトルを使用しますが、型変換には時間がかかる場合があります)。
set.seed(0)
N = 3E8
p = 0.02
x = sample(c(TRUE, FALSE), N, prob = c(p, 1-p), replace = TRUE)
y = sample(c(TRUE, FALSE), N, prob = c(p, 1-p), replace = TRUE)
いくつかの明白な方法:
table
bigtabulate
- 単純な論理演算(例
sum(x & y)
) - ベクトル乗算(ブーイング)
data.table
- 上記の一部
parallel
、multicore
パッケージ(または新しいparallel
パッケージ)から
私は最初の3つのオプション(私の答えを参照)を突き刺しましたが、もっと良いものともっと速いものがあるに違いないと感じています。
table
動作が非常に遅い ことがわかりました。bigtabulate
論理ベクトルのペアにとってはやり過ぎのようです。最後に、バニラ論理演算を実行することは厄介なことのように見え、処理中に大量の追加メモリをいっぱいにすることは言うまでもなく、各ベクトルを何度も調べます(3X?7X?)。これは膨大な時間の浪費です。
ベクトル乗算は通常は悪い考えですが、ベクトルがスパースである場合は、それをそのまま保存してからベクトル乗算を使用することで利点が得られる場合があります。
自由に変更して、それが集計関数の興味深い動作を示す場合は、自由に変更N
してください。p
:)
table
更新1.私の最初の答えは、3つの素朴な方法のタイミングを示しています。これは、遅いと信じる根拠です。しかし、理解すべき重要なことは、「論理的」な方法は非常に非効率的であるということです。それが何をしているのか見てください:
- 4つの論理ベクトル演算
- 4つの型変換(論理から整数またはFP-for
sum
) - 4つのベクトルの合計
- 8つの割り当て(論理演算用に1つ、合計用に1つ)
それだけでなく、コンパイルも並列化もされていません。それでも、それはまだズボンを打ち負かしtable
ます。、追加の型変換()を使用しても、がビートになることbigtabulate
に注意してください。1 * cbind...
table
更新2.Rの論理ベクトルがサポートNA
していること、およびこれらのクロス集計のシステムのレンチになることを誰もが指摘しないように(ほとんどの場合に当てはまります)、私のベクトルはis.na()
またはから来ていることを指摘する必要がありis.finite()
ます。:)私はデバッグNA
やその他の非有限値を使用してきましたが、最近は頭痛の種になっています。すべてのエントリがであるかどうかわからない場合はNA
、でテストすることができますany(is.na(yourVector))
。これは、このQ&Aで生じるアイデアのいくつかを採用する前に賢明です。
更新3.BrandonBertelsenはコメントで非常に合理的な質問をしました:サブサンプル(結局のところ、初期セットはサンプルです;-))がクロスを作成する目的に十分であるのに、なぜこれほど多くのデータを使用するのですか?集計?統計にあまり深く入り込まないでください。ただし、データは、TRUE
両方の変数について、観測が非常にまれな場合から発生します。1つはデータ異常の結果であり、もう1つはコードのバグの可能性によるものです(計算結果のみが表示されるため、バグの可能性があります。変数x
を「ガベージイン」およびy
「ガベージアウト」と考えてください。結果として、質問は、コードによって引き起こされる出力の問題が、データが異常である場合だけであるのか、それとも良いデータが悪くなる他の例があるのかということです(これが私が質問した理由です、、、またはが検出されたときNaN
に停止NA
Inf
します。)
TRUE
これは、私の例の値の確率が低い理由も説明しています。これらは実際には0.1%未満の時間で発生します。
これは別のソリューションパスを示唆していますか?TRUE
はい:2つのインデックス(つまり、各セット内のの位置)を使用して、セットの共通部分をカウントできることを示しています。交差点を実行する前にセットの要素を最初に並べ替えるMatlab(はい、これはRですが、我慢してください)によってしばらく前に燃やされたため、セットの交差点を避けました。(私は漠然と複雑さがさらに恥ずかしかったことを思い出します:O(n^2)
代わりにのようにO(n log n)
。)