こんにちは,米国データサイエンティストのかめ(@usdatascientist)です.
データサイエンスのためのPython入門第31回です(講座の目次はこちら).今回はosモジュールとpathlibモジュールを使って,安全にPath操作をする方法を紹介します.
(「データサイエンスのためのPython講座」動画版がでました!詳細はこちら)
osモジュールのosはOperating SystemのOSと同じです.前回と前々回で,ファイルパスを文字列で操作して, .split() 関数を使ってファイル名やフォルダ名を取得していました.
しかしファイルパスというのはOSによって変わりますよね?今回はLinux上で動かしているのでスラッシュ( / )でフォルダを区切っていますが,Windowだとバックスラッシュ( \ )だったりします.
ファイルパスはOSによって異なりますし,スラッシュをつけ忘れてたりしてバグの元なので文字列操作だけでは不安です.文字列ではなくてosモジュールを使うことで,安全にpathを操作できます.
実際の開発ではosモジュールを使い,自分の環境で動かすだけのコードなら文字列を使って簡単に書くイメージでいいと思います.
日頃からosモジュールを使うと忘れずに済みますが,文字列を使ったほうが簡単なので私はついつい文字列を使ってしまってます笑
重要なのは「文字列のファイルパス操作はOSによってはうまく動かない」事を念頭に置いておくということと,「osモジュールを使ってより安全に書ける」事を知っておく事だと思います.
以上の点を踏まえて,今回はosモジュールを使ったpathの操作についてやっていきます.
また,ファイルパスを取得するところでpathlibというモジュールを使います.合わせて説明します.
今回の内容は普段解析で常に使うものでもないので,多くの人は都度ネットで確認しながら書くようなコードだと思います.なので覚えようとはせず,必要な時にググればいいくらいに読んでください
目次
osモジュールとpathlibモジュールをインポートする
どちらもpythonにもともと入っているモジュールなのでインストールは不要です.それぞれどういうモジュールかは,使い方を勉強する過程で理解すればOKです.
以下のようにしてインポートします.
1 2 |
import os from pathlib import Path |
osモジュールは import os とシンプルにインポートすればOKです.
pathlibモジュールは,今回はPathクラスを使用するので from pathlib import Path とします.
pathlibを使ってフォルダおよびファイル構造を取得
第29回でglobを使ったファイルパスのリストを取得しました.今回はより安全に,pathlibを使って取得してみましょう!
第29回同様,今回もKaggleの「Diabetic Retinopathyデータセット」を使ってみます.第29回にそってデータを準備してください.
さて,早速pathlibを使って保存した’gaussian_filtered_images’のフォルダ構造を取得しましょう.
Path()にフォルダ名を指定してPathオブジェクトを作ります.
1 |
p = Path('gaussian_filtered_images') |
pというPathオブジェクトのインスタンスを作成しました.
さて,いきなりpというPathオブジェクト(正しくはPosixPathオブジェクト)を作りましたが,これはなんでしょうか?笑
このpの中には,gaussian_filtered_images配下の情報が入っています.このpを使って色々な情報を取得することができます.
.iterdir() を使って中に入っている配下のフォルダ情報をみてみましょう. p.iterdir() はfor文とかで回せるもの(イテレータのこと.これは正しくはジェネレータだが,ジェネレータはイテレータの一種.)なので,list()関数に入れる事でリスト化して中身をみてみましょう.
1 2 |
p = Path('gaussian_filtered_images') list(p.iterdir()) |
1 2 3 4 5 6 7 |
[PosixPath('gaussian_filtered_images/.DS_Store'), PosixPath('gaussian_filtered_images/export.pkl'), PosixPath('gaussian_filtered_images/Mild'), PosixPath('gaussian_filtered_images/Moderate'), PosixPath('gaussian_filtered_images/Proliferate_DR'), PosixPath('gaussian_filtered_images/Severe'), PosixPath('gaussian_filtered_images/No_DR')] |
それでは,第29回でやったように全てのpngファイルのファイルパス情報のリストを作ってみましょう.
第29回でglob関数と * (アスタリスク)を使うことで特定のパターンにマッチするファイルパスのリストを取得できました.
実は,このPathクラスに glob() 関数が装備されてます(!!) ということで同じようにglob関数を使ってpngファイルのpathリストを取得しましょう^^
p.glob() 関数にパスのパターンをいれます.これもジェネレータなのでlist()に入れて中身を表示してみましょう.
1 |
list(p.glob('*/*.png')) |
pathlibの使い方はだいたい本記事で紹介している内容が基本的な使い方です.理解する必要もなければ無理して覚えなくてもいいかもしれません.必要になったらこの記事に戻って,最初はコピペして自分で色々といじってみてだんだん使えるようにすればOKです.
なので,「これがイテレータで〜」とか「インスタンスが〜」とかは今は無理して覚えなくてOK!!
以上のようにしてファイルやフォルダの構造をイテレータで取得できます.(*イテレータというのはリストとかdf.iterrows()のようにfor文などで回せるオブジェクトです.)
ファイルパスを文字列で取得するにはPathオブジェクトの .as_posix() 関数をコールします.覚えなくていいです.毎回コピペしましょう.
1 |
list(p.glob('*/*.png'))[0].as_posix() |
1 |
'gaussian_filtered_images/Mild/2d7666b8884f.png' |
.as_posix()関数はOSによらずスラッシュ( / )で文字列連結して返してくれます.
...それはわかったけど,これらをどうやって使えばいいのか??
それを今から説明していきます.このPathオブジェクトに対してosモジュールを使って色々と操作します!
osモジュールでpathをjoin・splitする
joinではファイル名をフォルダに連結してそのファイルパスを作成でき,splitではファイルパスをそれぞれのフォルダ名で分割してリストにすることができます.
第29回でやっていた文字列操作と同じです.
使い方は簡単で,os.path.joinpath()およびos.path.split()を使います.以下に例を見てみてください.
まずは準備です.先ほどの復習です.今回はgaussian_filtered_images配下のフォルダを一つサンプルで使ってます.
1 2 3 4 5 6 7 |
#先程までの復習 p = Path('gaussian_filtered_images') #一つサンプルを選ぶ folder = list(p.iterdir())[3] print(folder) # folderはPathオブジェクトであることに留意 print(type(folder)) |
1 2 |
gaussian_filtered_images/Moderate <class 'pathlib.PosixPath'> |
このfolderインスタンスに対してos.path.join()とos.path.split()を使ってみましょう
1 2 3 4 5 |
#-------ここからosモジュールを使う------ split_list = os.path.split(folder) print(split_list) file_path = os.path.join(folder, 'test.txt') print(file_path) |
文字列でやっていたPath操作をこのようにosモジュールを使ってできます.
次は,このosモジュールで実際にフォルダを作成してみましょう.
os.path.exists()でフォルダの有無を確認して無ければos.makedirs()でフォルダを作成する
pythonでフォルダを作る時は,大抵この流れで作ります.
- os.path.exists() でフォルダが無いことを確認
- フォルダが無ければ os.makedirs() でフォルダを作成
それではコードをみてみましょう!
今回はgaussian_filtered_imagesフォルダの下にnew_folderフォルダを作ってみます
作成するPathを以下のようにして作ります.
1 2 3 4 5 |
p = Path('gaussian_filtered_images') new_folder_name = 'new_folder' new_folder_path = os.path.join(p, new_folder_name) #作られたpathを確認する print(new_folder_path) |
それでは, os.path.exists() と os.makedirs() を組み合わせてフォルダを作ります.
os.path.exists() の引数にファイルパスを指定すると,フォルダの有無をTrue, Falseで返してくれます.
1 |
os.path.exists(new_folder_path) |
1 |
False |
1 2 |
if not os.path.exists(new_folder_path): os.makedirs(new_folder_path) |
1 |
os.path.exists(new_folder_path) |
1 |
True |
さて,この状態で再度os.makedirs()を実行するとどうなるかみてみましょう.
1 |
os.makedirs(new_folder_path) |
Errorが返ってきます.なので最初に条件をつけて実行しました.すでに存在する場合は上書きして作らない方がいいです.データが消えますからね...
基本はこのように「無ければ作成」しましょう.
まとめ
今回はosモジュールとpathlibモジュールを組み合わせたpath操作について学習しました.
製品開発でこのようなpath操作をする場合は,これらのモジュールを使って操作した方が安全です.が,普段ちょっとしたデータ解析をするだけであればここまでちゃんとやる必要も無いかもしれません.単純に文字列を操作した方が楽ですからね.
ただ,文字列を操作する際には,スラッシュ( / )をつけ忘れないように注意しましょう.
今回学んだの以下の通りです.
- import os でosモジュールをインポート
- from pathlib import Path でPathクラスをインポート
- Path() にパスを指定してPathオブジェクトを作成.
- Pathオブジェクトの iterdir() をコールすることでイテレータを取得
- Pathオブジェクトの glob() にフォルダパスのパターンを指定することでマッチしたファイルパスだけ取得
- os.path.split() にPathオブジェクトを入れることでフォルダ名とファイル名を分割したリストを取得
- os.path.join() の第一引数にPathオブジェクト,第二引数に文字列を入れることで,連結してファイルパスを取得
- os.makedirs() にフォルダパスを文字列で指定することでフォルダを作成する
- フォルダ作成時には os.path.exists() でフォルダが無いことを事前に確認しておくこと
長くなってしまいましたが,データサイエンスは当然データを扱うのでファイルパスを操作する機会が非常に多いです.
文字列でもやりたいことはできますが,このようにそれ用のモジュールを使うことでより安全に操作することを覚えておきましょう.
最初はなかなか使い慣れないと思います.私もよくごっちゃになります.
その時はこのページにきたりググったりして都度お手本のコードを参考にしながら使ってみてください.
それでは!
追記)次回の記事書きました!次回は並列処理をします.大量のデータを扱う場合に欠かせないのが並列処理です.Pythonでは簡単に書ける反面,いろんな書き方ができてしまうので初学者の方は結構迷うと思います.とりあえずこの記事の内容だけ押さえておけばOKです.