前回、R標準パッケージ(base)とstringrパッケージの比較をしてみて、「処理速度は、場合によってはbase、場合によってはstringrの方が速い」ということがわかった。
Rで文字列操作を行う際に、標準パッケージ(baseパッケージ)やstringrパッケージを使っていることが多いと思う。 私の周囲にはstringrを好む人が多いけれども、実際、どちらを使った方がよいのか、調べてみた。 R …
で、具体的にどのときにbase、どのときにstringrが速いのか、調べてみた。
処理速度に関する違い
stringr の方が速い場合
- ベクトル化された処理が可能なため、
stringr
の方が速くなることがある。 - 一貫したC++コード (stringi) に基づいているため、文字列処理が効率的。
- **大規模なデータ(複数の行やリスト)**を処理する際、
stringr
は内部的にC++で並列処理を行うケースがあり、base R
よりも速くなる可能性がある。
base R の方が速い場合
- 単一の文字列操作(小さなデータ、1行のテキスト操作)では
base R
が速い。 - 正規表現のパフォーマンスは、
base R
はCレベルで実装されているため、小規模のテキストでは速いことが多い。 - オーバーヘッドが少ない:
stringr
はstringi
をバックエンドで呼び出すため、関数呼び出しのオーバーヘッドが生じる。
ベンチマークの比較
実際の速度の違いをテストしてみた。
- テスト1: 大規模なデータ(10万行の文字列)に対する置換処理
- テスト2: 小規模なデータ(1行の文字列)に対する置換処理
……実際のベンチマークを行い、どちらが速いか確認してみる。
大規模なデータ(10万行の文字列)に対する置換処理
方法 | 速度(ms) |
base | 0.12850850000063474 |
stringr | 0.06725080000080652 |
小規模なデータ(1行の文字列)に対する置換処理
方法 | 速度(ms) |
base | 0.0001371550000044408 |
stringr | 0.00014540600000145787 |
結果、大規模データはstringrの方が断然早く、小規模データはbaseの方が僅かに速い、とゆー結果に。
ただ、結論としては、「どちらも速い」と言えると思う。。。
速さの理由
一応、速さの理由を上げておく。
なぜ大規模データでstringrが速くなるのか?
- 並列処理の最適化
stringr
は内部的にstringi
ライブラリ(C++で書かれたライブラリ)を使っており、並列処理の最適化が行われる場合がある。- 特に、大きなベクトルデータ(100,000行のデータ)を一度に処理すると、C++の並列化が有効になるため、baseよりも速くなる可能性がある。
- ベクトル処理の違い
base R
の関数は1つ1つの要素に対して繰り返し処理を行うイメージだが、stringr
はベクトル全体に対してバルク処理(まとめて処理)を行うため、データが大きい場合はstringr
の方が有利になることがある。
なぜ小規模データでbase
の方が速いのか?
- オーバーヘッドの違い
base R
のgsub()
は関数呼び出しのオーバーヘッドが少ないため、小さな処理はbaseの方が速い。- 一方、
stringr
は内部的にstringi
の関数を呼び出すため、呼び出しのオーバーヘッドが少しだけ大きいことが原因。
- 関数のシンプルさ
- 小さな文字列では
base R
のgsub()
は非常に軽量で、メモリの消費量も少ないため、わずかに速い。
- 小さな文字列では
結論をまとめると、こんな感じ▼
データの規模 | おすすめの関数 | 理由 |
---|---|---|
小規模データ(1行の文字列) | base (gsub ) |
オーバーヘッドが少なく、速い |
大規模データ(10万行のデータ) | stringr (str_replace_all ) |
C++最適化による並列処理が速い |
コードの可読性が重要 | stringr |
一貫したstr_ の名前で可読性が高い |
リンク
リンク
リンク
リンク