R logo

前回、R標準パッケージ(base)とstringrパッケージの比較をしてみて、「処理速度は、場合によってはbase、場合によってはstringrの方が速い」ということがわかった。

で、具体的にどのときにbase、どのときにstringrが速いのか、調べてみた。

処理速度に関する違い

stringr の方が速い場合

  • ベクトル化された処理が可能なため、stringrの方が速くなることがある。
  • 一貫したC++コード (stringi) に基づいているため、文字列処理が効率的。
  • **大規模なデータ(複数の行やリスト)**を処理する際、stringrは内部的にC++で並列処理を行うケースがあり、base Rよりも速くなる可能性がある。

base R の方が速い場合

  • 単一の文字列操作(小さなデータ、1行のテキスト操作)ではbase Rが速い。
  • 正規表現のパフォーマンスは、base RはCレベルで実装されているため、小規模のテキストでは速いことが多い。
  • オーバーヘッドが少ない:stringrstringiをバックエンドで呼び出すため、関数呼び出しのオーバーヘッドが生じる。

ベンチマークの比較

実際の速度の違いをテストしてみた。

  • テスト1: 大規模なデータ(10万行の文字列)に対する置換処理
  • テスト2: 小規模なデータ(1行の文字列)に対する置換処理

……実際のベンチマークを行い、どちらが速いか確認してみる。

大規模なデータ(10万行の文字列)に対する置換処理

方法 速度(ms)
base 0.12850850000063474
stringr 0.06725080000080652

小規模なデータ(1行の文字列)に対する置換処理

方法 速度(ms)
base 0.0001371550000044408
stringr 0.00014540600000145787

 

結果、大規模データはstringrの方が断然早く、小規模データはbaseの方が僅かに速い、とゆー結果に。

ただ、結論としては、「どちらも速い」と言えると思う。。。

速さの理由

一応、速さの理由を上げておく。

なぜ大規模データでstringrが速くなるのか?

  1. 並列処理の最適化
    • stringrは内部的にstringiライブラリ(C++で書かれたライブラリ)を使っており、並列処理の最適化が行われる場合がある。
    • 特に、大きなベクトルデータ(100,000行のデータ)を一度に処理すると、C++の並列化が有効になるため、baseよりも速くなる可能性がある。
  2. ベクトル処理の違い
    • base Rの関数は1つ1つの要素に対して繰り返し処理を行うイメージだが、stringrはベクトル全体に対してバルク処理(まとめて処理)を行うため、データが大きい場合はstringrの方が有利になることがある。

なぜ小規模データでbaseの方が速いのか?

  1. オーバーヘッドの違い
    • base Rgsub()は関数呼び出しのオーバーヘッドが少ないため、小さな処理はbaseの方が速い。
    • 一方、stringrは内部的にstringiの関数を呼び出すため、呼び出しのオーバーヘッドが少しだけ大きいことが原因。
  2. 関数のシンプルさ
    • 小さな文字列ではbase Rgsub()は非常に軽量で、メモリの消費量も少ないため、わずかに速い。

 

結論をまとめると、こんな感じ▼

データの規模 おすすめの関数 理由
小規模データ(1行の文字列) base (gsub) オーバーヘッドが少なく、速い
大規模データ(10万行のデータ) stringr (str_replace_all) C++最適化による並列処理が速い
コードの可読性が重要 stringr 一貫したstr_の名前で可読性が高い