ケィオスの時系列解析メモランダム

時系列解析,生体情報学,数学・物理などの解説です.

【Rでファイルの一括処理】正規表現とワイルドカードの活用

前回,フォルダ内にあるたくさんのファイルについて,フォルダ内にある全ファイル名を取得するRのコマンドとしてlist.files(...)の使い方を紹介しました.今回は,ファイル名に含まれる文字を使って,特定のファイルを見つける方法を説明します.今回,メインで説明するのは,正規表現ワイルドカードの使い方です.とはいえ,そんなに詳しくは説明しません.

 list.files(...)を使うと,サブフォルダも含めてすべてのファイルを探索してくれるので,便利です.一方で,見つかったたくさんのファイルの中から,自分が分析したいファイルを探すのに苦労することがあります.そのような苦労を軽減するために,ファイル名を付けるときに,必要な情報 (計測IDや計測日時)をファイル名に入れると良いでしょう.さらに,ファイルの拡張子として独自なものを指定するのも良いと思います.Rで処理することを前提としたテキストファイルであれば,拡張子は"txt"や"csv"でなくても構いません.

 今回は前回の記事 (以下のリンク)の補足です.

chaos-kiyono.hatenablog.com

特定の拡張子のファイルを探す

 拡張子の違いを使って,ファイルの種類を分類するのは,コンピュータの世界では一般的な方法です.list.files(...)で探すファイル名について,拡張子を指定する場合,例えば,拡張子が".csv"であれば,

DIR <- "C:/Document/Example/Folder" #これは,パスの例です.各自指定してください.
FN <- list.files(DIR, pattern="\\.csv$")

とします.このとき,FNに,指定した条件とあうファイル名のリスト (ファイル名のベクトル)が格納されます.バックスラッシュ\は,日本語環境ではに対応します.

 今回説明したいのは,上のスクリプトにある pattern="\\.csv$"の部分です."\\.csv$"に含まれる,\\.$は,正規表現と呼ばれる文字列の形式を指定するコマンドです.patternには,正規表現を使って文字の形式を指定しているのです.ここでのポイントは,以下です.

ドット.正規表現\\. になる.

$はファイル名の末端位置を指定している.

 これらのポイントを踏まえれば,"\\.csv$"は,「ファイル名の最後に .csv が付いている」という条件を表しています.

 正直,拡張子がcsvのファイルを読み込むときは,pattern="csv"と指定すれば,大丈夫なことが多いです.しかし,これだと,ファイル名の途中に"csv"が含まれるファイル名

"csv_reader.exe", "docsvictory.txt"

なんかも,条件に一致してしまいます.

 コンマの後に"csv"が続いていること,"csv"でファイル名が終わっていることを指定したほうがより正確なので,pattern="\\.csv$"とします.

正規表現じゃなくて,ワイルドカードを使いたい

 文字列の構成を指定する方法として,Unixシェルスクリプトや,Windowsのバッチファイルで使っていたワイルドカードというのがあります.私が主に使うワイルドカード*です.*は任意の長さの文字列を表し,文字はアルファベットでも,数字でも,記号でも,なんでも構いません.ファイル名に"2022"が含まれる"csv"ファイルを指定したいとき,ワイルドカードを使えば,

"*2022*.csv"

と表現できます.この条件には,

"2022_RRI.csv", "01_20220913.csv", "RRI20220913.csv"

などが引っかかります.ワイルドカード*は,正規表現では別の意味になります.

 私はワイルドカードの方が,正規表現よりも慣れているので,Rでもワイルドカードで指定したいなと思っていたら,本日,glob2rx(...)というコマンドの存在を知りました.このコマンドを使えば,ワイルドカードでの表現を,正規表現に直してくれます.

 例えば,ワイルドカードで記述した"*2022*.csv"を,正規表現に直したければ,

glob2rx("*2022*.csv")

とします.結果は,

[1] "^.*2022.*\\.csv$"

と出力されます.正規表現だと表現が複雑になるので,記憶力のない私はワイルドカードの方が好きです.

 ということで,私と同じようにワイルドカードに慣れている人は,

FN <- list.files(DIR, pattern=glob2rx("*2022*.csv"))

のように,すれば良いということです.

 ただ,ワイルドカード*を,正規表現に変えるのは簡単で,

ってことです.

正規表現を使いこなせれば意外と便利

 正規表現を使えば,ファイル名の構造を使って特定のファイルを探すのが楽になります.正規表現について説明してあるページはたくさんあるので,詳しいことは,自分で調べてみてください.以下では,正規表現の具体例をいくつか紹介します.

アルファベットで構成されるファイル名

 被験者を表すA~Jと,2つの実験条件を表すOとPを組み合わせたファイル名
"A_O.csv", "A_P.csv", "B_O.csv", "B_P.csv", ..., "J_O.csv", "J_P.csv"
を探したいとします.このとき,DIRにフォルダへのパスを指定して,

FN <- list.files(DIR, pattern="^[A-J]_(O|P)\\.csv$")

とします.

 正規表現を使った"^[A-J]_(O|P)\\.csv$" の意味を分解すると,

^ 先端位置
[A-J] A~Jの大文字アルファベットが一文字
_ アンダーバー"_"
(O|P) OかPの一文字
\\. ドット"."
csv "csv"
$ 終端位置

となります.

性別,年齢,計測日から構成されるファイル名

 被験者の性別 ("Female", "Male"),年齢 (数値),計測日 (yyyymmdd)を組み合わせたファイル名,
"Female_32_20220913.csv", "Female_25_20220829.csv", "Male_28_20210121.csv", "Male_24_20200723.csv", ...
の中で,2022を含むものを探したいとします.このとき,DIRにフォルダへのパスを指定して,

FN <- list.files(DIR, pattern="^(Female|Male)_[0-9]*_2022[0-9]*\\.csv$")

とします.

 正規表現を使った"^(Female|Male)_[0-9]*_2022[0-9]*\\.csv$" の意味を分解すると,

^ 先端位置
(Female|Male) "Female"か"Male"のどちらか
_ アンダーバー"_" (そのまま)
[0-9] 0~9の数字が1文字
[0-9]* 数字が複数つながっている
2022 "2022" (そのまま)
\\. ドット"."
csv "csv" (そのまま)
$ 終端位置

となります.

 こんなに詳細に指定しなくても,フォルダ内に解析対象のファイルしかなければ,

FN <- list.files(DIR, pattern="_2022")

とするだけです.