R言語:dir()で取得したフォルダパスを、階層ごとに区切ってDataFrameに格納する
ファイル/フォルダのフルパスを取得した際、予め階層ごとに区切って持っておく*1と、『特定の階層にいる、あるファイル』なんて指定して集計する作業*2が捗ります。
基本は、dir()で取得したフルパスを\で区切ってからDataFrame化するのですが、
そこで一つ躓いたので備忘録がてらに以下メモ
(…車輪の再発明でないことを祈ります)
もくじ
参考:当方の環境(sessionInfo())
まったくバージョン上げてない
> sessionInfo() R version 3.4.2 (2017-09-28) Platform: x86_64-w64-mingw32/x64 (64-bit) Running under: Windows >= 8 x64 (build 9200)
やりたいこと
たとえば、こんな感じのディレクトリに対して、C:以下の全ファイル/フォルダのフルパスをまるっと取ってくる
C: ├hogehoge01 │├fugafuga01_01 ││├piyopiyo01_01_01 │││└pitcture01_01_01_01.png ││└memo01_01_01.txt │├fugafuga01_02 │└memo01_01.txt ├hogehoge02 │└memo02_01.txt ├hogehoge03 │└fugafuga03_01 │ └pitcture03_01.png └pitcture01.png
そんで取ってきたフルパスに対して、階層ごとに区切ってDataFrameに格納することを考える
dir01 | dir02 | dir03 | dir04 |
---|---|---|---|
hogehoge01 | |||
hogehoge01 | fugafuga01_01 | ||
hogehoge01 | fugafuga01_01 | piyopiyo01_01_01 | |
hogehoge01 | fugafuga01_01 | piyopiyo01_01_01 | pitcture01_01_01_01.png |
hogehoge01 | fugafuga01_01 | memo01_01_01.txt | |
hogehoge01 | fugafuga01_02 | ||
hogehoge01 | memo01_01.txt | ||
hogehoge02 | |||
hogehoge02 | memo02_01.txt | ||
hogehoge03 | |||
hogehoge03 | fugafuga03_01 | ||
hogehoge03 | fugafuga03_01 | pitcture03_01.png | |
pitcture01.png |
(※合っているか不安)
やったこと(Bad tip)
まず、指定階層以下のフォルダ/ファイル一覧を、何も考えずにdir()で取ってきてDataFrame化するとこうなる
コード
D_path <- "C:" FileLists <- dir(path = D_path, recursive = T) FileLists <- as.data.frame(FileLists) FileName <- strsplit(as.character(FileLists$FileLists), "\\/") DF_result <- do.call(rbind, FileName) DF_result <- as.data.frame(DF_result)
出力結果(※イメージ)
V1 | V2 | V3 | V4 |
---|---|---|---|
hogehoge01 | hogehoge01 | hogehoge01 | hogehoge01 |
hogehoge01 | fugafuga01_01 | hogehoge01 | fugafuga01_01 |
hogehoge01 | fugafuga01_01 | piyopiyo01_01_01 | hogehoge01 |
hogehoge01 | fugafuga01_01 | piyopiyo01_01_01 | pitcture01_01_01_01.png |
hogehoge01 | fugafuga01_01 | memo01_01_01.txt | hogehoge01 |
hogehoge01 | fugafuga01_02 | hogehoge01 | fugafuga01_02 |
hogehoge01 | memo01_01.txt | hogehoge01 | memo01_01.txt |
hogehoge02 | hogehoge02 | hogehoge02 | hogehoge02 |
hogehoge02 | memo02_01.txt | hogehoge02 | memo02_01.txt |
hogehoge03 | hogehoge03 | hogehoge03 | hogehoge03 |
hogehoge03 | fugafuga03_01 | hogehoge03 | fugafuga03_01 |
hogehoge03 | fugafuga03_01 | pitcture03_01.png | hogehoge03 |
pitcture01.png | pitcture01.png | pitcture01.png | pitcture01.png |
階層が一番深いファイルについては、想定した通り、各階層ごとに列がわかれてDataFrameに格納されている
しかし、階層が浅いファイル/フォルダでは、階層のない部分にも値が入ってしまっている
本当ならば、階層の浅いファイル/フォルダについては、以降の階層(DataFrameの列)にはNAが入っていてほしい
どうにかならんか
長さの違うリストを平和に結合する方法、少しググってみると、こんな感じの答えが出た
stackoverflow.com
状況としてはこの人と似ている(dir()の結果をstrsplit()に入れたときの出力は、長さの違うvectorのlistになっている*3 )
発生している現象も、これに近い
どうやら、長さの違うvectorをcbind()やrbind()で結合しようとすると、短い要素の足りない部分については、存在している部分を繰り返して埋める動きをするっぽい
解決策として、2番目の回答のqpcR::cbind.na()がスマートでよさげだったけど、qpcR::rbind.na()はないため断念
1番目の回答の主旨である、『短い方ベクトルの空いているところにNAを入れれば、cbindできるよ(超意訳)』が参考になりそう
やったこと(Better? tip)
そこで思いついたのが以下の方法
コード
D_path <- "C:\\hogehoge" FileLists <- dir(path = D_path, recursive = T) FileLists <- as.data.frame(FileLists) FileName <- strsplit(as.character(FileLists$FileLists), "\\/") Tmp <- lapply(FileName, function(x){c(x, rep(NA, (5-length(x))))}) DF_result <- do.call(rbind, Tmp) DF_result <- as.data.frame(DF_result)
出力結果(※イメージ)
やったー!それっぽいのができたー!!
V1 | V2 | V3 | V4 | V5 |
---|---|---|---|---|
hogehoge01 | NA | NA | NA | NA |
hogehoge01 | fugafuga01_01 | NA | NA | NA |
hogehoge01 | fugafuga01_01 | piyopiyo01_01_01 | NA | NA |
hogehoge01 | fugafuga01_01 | piyopiyo01_01_01 | pitcture01_01_01_01.png | NA |
hogehoge01 | fugafuga01_01 | memo01_01_01.txt | NA | NA |
hogehoge01 | fugafuga01_02 | NA | NA | NA |
hogehoge01 | memo01_01.txt | NA | NA | NA |
hogehoge02 | NA | NA | NA | NA |
hogehoge02 | memo02_01.txt | NA | NA | NA |
hogehoge03 | NA | NA | NA | NA |
hogehoge03 | fugafuga03_01 | NA | NA | NA |
hogehoge03 | fugafuga03_01 | pitcture03_01.png | NA | NA |
pitcture01.png | NA | NA | NA | NA |
言い訳
本当はrep(NA, (5-length(x)))の5としているところを、list内のvectorの最大サイズから持ってこれるとスマートなんだろうけど、list型はどうも苦手*4なので断念。
集計かける分には(ひとまず)困っていないので、とりあえずはこれで。
もしstrsplit()の返り値がDataFrameならば、以下の手段が使えたのでもっとラクスマートになったんだろうな
stackoverflow.com
[R] How to rbind list of vectors with unequal vector lengths?
R: Combining vectors or data frames of unequal length into one data frameryouready.wordpress.com
本当はこのあとddply()使って集計かけたんだけど、今日はひとまずここまで。*5
#R言語は個人的には扱いやすくて好きなのですが、毎回list型の扱いには難儀してます…