4-3.保存フォルダを自動で作成しよう
基本的に,Pythonにおけるファイル入出力は実行ファイル.pyと同じパスで行われます.しかし,学術的なシミュレーションでは大量の.csvファイルなどを入出力することが多く,一つのフォルダだけでこれらを管理することは非常に非効率です.そこで,Pythonからファイルの入出力を行うフォルダを変更してあげる必要があります.
(1) カレントディレクトリ
Pythonによるファイル入出力を理解するには,カレントディレクトリ(cd)の概念を理解する必要があります.cdの概念はコマンドプロンプトから学ぶことが出来ます.まずはコマンドプロンプトを開きましょう.すると,C:\Users\K.Hagagawaのような表示が出てきたはずです.これがcdです.コマンドプロンプトは今このディレクトリを見ています.このcdでPythonもファイルの入出力を行います.ファイルの入出力を行うフォルダを変更するというのはcdを変えるということです.cdをコマンドプロンプト上で変えたければcd ディレクトリを入力すればOKです.フルパスでもOKですが,C:\Users\K.Hagagawa\program filiesのようにcdの下層にあるディレクトリであれば,cd 下層パスで指定するディレクトリに移動できます.今回はcd \ program filiesとなります.
Pythonによるファイル入出力を理解するには,カレントディレクトリ(cd)の概念を理解する必要があります.cdの概念はコマンドプロンプトから学ぶことが出来ます.まずはコマンドプロンプトを開きましょう.すると,C:\Users\K.Hagagawaのような表示が出てきたはずです.これがcdです.コマンドプロンプトは今このディレクトリを見ています.このcdでPythonもファイルの入出力を行います.ファイルの入出力を行うフォルダを変更するというのはcdを変えるということです.cdをコマンドプロンプト上で変えたければcd ディレクトリを入力すればOKです.フルパスでもOKですが,C:\Users\K.Hagagawa\program filiesのようにcdの下層にあるディレクトリであれば,cd 下層パスで指定するディレクトリに移動できます.今回はcd \ program filiesとなります.
Pythonに話を戻せば,cdは基本的に実行する.pyファイルがある場所になります.あるいは,エディタがプロジェクトフォルダを予め指定していればそこがcdとなります.プロジェクトフォルダというのは,メインの実行ファイルを中心にその実行に伴う各種ファイル(.csvや.txtなど)が格納されたcdに相当するフォルダを指します.実行する.pyファイルがあるディレクトリとは別のディレクトリがプロジェクトフォルダとして設定されていた場合,実行に必要な.csvファイルを見つけられなかったり,期待した場所にファイルが出力されないこととなるので注意しましよう.単純に,作成した.pyファイルが一度も保存されておらず,cdが存在しないケースもあります.
では,どうやってカレントディレクトリを探すのか?これは,pythonでファイルを出力すれば良いのです.Pythonで作った何かしらのデータを出力するコードを書き,実際に指定したファイルが生成された場所が.pyファイルのcdです.前ページにあったwith_write.pyはその一例になります.
(2) Pythonによるディレクトリの変更
Pythonは基本的にカレントディレクトリ内でファイルの入出力を行います.しかし,学術的なシミュレーションのように多数のファイルを入出力するケースでは,これらのファイルによって.pyファイルが埋もれてしまったり,入出力ファイルの区別がつかなくなってしまったりととても不便です.もし,pythonのプログラム上でcdを変更し,読み書きするファイルのあるフォルダを変えることができれば非常に便利です.Pythonの標準装備関数にosがあり,これが可能です.ここでは,osを用いたcdの変更やフォルダの自動生成,出力ファイル名の自動生成方法を解説します.
Pythonは基本的にカレントディレクトリ内でファイルの入出力を行います.しかし,学術的なシミュレーションのように多数のファイルを入出力するケースでは,これらのファイルによって.pyファイルが埋もれてしまったり,入出力ファイルの区別がつかなくなってしまったりととても不便です.もし,pythonのプログラム上でcdを変更し,読み書きするファイルのあるフォルダを変えることができれば非常に便利です.Pythonの標準装備関数にosがあり,これが可能です.ここでは,osを用いたcdの変更やフォルダの自動生成,出力ファイル名の自動生成方法を解説します.
osには様々な関数がありますが,ディレクトリ関係に絞れば以下の通りになります.これをPythonのインタラクティブモードで確認してみます.
os.ディレクトリ系関数
関数 | 動作 |
---|---|
os.getcwd | カレントディレクトリを表示 |
os.dirname | ディレクトリを表示 |
os.chdir | ディレクトリを移動する |
os.mkdir | ディレクトリを作る |
os.makedirs | ディレクトリを作る(推奨) |
os.listdir | ディレクトリの中を全てリストにする |
os.path.isdir | ディレクトリかどうか.あればTrue,なければFalse |
>>> import os >>> os.getcwd <built-in function getcwd> >>> os.getcwd() 'C:\\Users\\K.Hagagawa' >>> os.chdir("../") >>> os.getcwd() 'C:\\Users' >>> os.mkdir("./temp") >>> os.listdir("./") ['All Users', 'Default', 'Default User', 'desktop.ini', 'Eclipse-ccp', 'K.Hagagawa', 'KA7D4~1~HAG', 'Public', 'temp'] >>> os.chdir("./temp") >>> os.listdir("./") []
( )を抜いたgetcdwを実行すると<built-in function getcwd>が出力されます.これはgetcdwがpythonの標準装備関数であることを示してくれています.次に( )を入れたgetcdw( )を実行すると,カレントディレクトリ'C:\\Users\\K.Hagagawa'が表示されます.次にos.chdir("../")を実行します.("../")における..は一つ前のパスに戻る事を意味しています.("./")は現在のパスを意味します.つまり,ピリオドの数がパスの位置を指定しています.よって,os.chdir("../")は一つ前のパスに戻るということです.ここで,再びgetcdw( )を実行すると'C:\\Users\\K.Hagagawa'の上層パスであるC:\\Usersにcdが移りました.このようにos.chdir(" ")使ってpython上でcdを変えられます.
実際にフォルダを作るにはos.mkdir( )を使います.引数は新たに生成するフォルダのパスです.今回は("./temp")とします.すると,cdに新たにフォルダが生成されています.それを確認するにはos.listdir("./")を実行し,cdにあるファルダやファイルのリストを出力させます.すると,os.mkdir("./temp")で生成したtempが生成されたことが分かるかと思います.次にos.chdir("./temp")を使って生成したtempフォルダに移動します.ここにはまだ何もありませんから,os.listdir("./")しても空のリストが出るだけです.
(3) フォルダ名を自動で設定する
とあるシミュレーションの出力先をos.mkdir("./temp")と設定し,再度これを実行するとFileExistsError: [WinError 183] 「既に存在するフォルダを作成することはできません」。と表示され,ファイルが出力されないトラブルに直面します.パラメータを変えるなどで毎回のシミュレーションの結果が変わるケースでは,同じパスに出力を行うのは得策ではありません.シミュレーションに合わせて毎回フォルダを変えるほうが親切です.そこで,os.mkdir("./temp")をシミュレーションの内容や実施時刻に合わせて変更し,そこに出力を保存する手法がしばしば採られます.まずは,シミュレーションのパラメータに合わせてフォルダ名を設定する方法を以下に示します.
とあるシミュレーションの出力先をos.mkdir("./temp")と設定し,再度これを実行するとFileExistsError: [WinError 183] 「既に存在するフォルダを作成することはできません」。と表示され,ファイルが出力されないトラブルに直面します.パラメータを変えるなどで毎回のシミュレーションの結果が変わるケースでは,同じパスに出力を行うのは得策ではありません.シミュレーションに合わせて毎回フォルダを変えるほうが親切です.そこで,os.mkdir("./temp")をシミュレーションの内容や実施時刻に合わせて変更し,そこに出力を保存する手法がしばしば採られます.まずは,シミュレーションのパラメータに合わせてフォルダ名を設定する方法を以下に示します.
os_parameter_folder.py
- import os
- import numpy as np
- row = 5
- colum = 10
- result = np.random.randint(0,10,(row,colum))
- dir = str(row)+”_”+str(colum)
- os.mkdir("./temp"+dir)
- os.chdir(“./temp"+dir )
- for i in range(row):
- out = result[i,:] #スライス
- np.savetxt(“Result_row_”+str(i)+”.csv”, out, delimiter =”,”)
-
パラメータrowとcolumはシミュレーション前に変更できる変数です.5行目のrandom.randintでrow×columの大きさを持つランダムな整数配列を[0,10)の範囲で生成します.次に,生成するフォルダ名を設定します.str( )を用いてrowとcolumを文字列とし,row_columという文字列dirを作り,os.mkdir("./temp"+dir)とすることでパラメータを反映したフォルダを作成できます.文字列は足し算できるという特徴を用いたテクニックです.ここを保存先とするのでos.chdir(“./temp"+dir )によってcdを変更することを忘れずに.最後にrow×columの大きさを持つランダムな整数配列を行ごとに出力します.ここで,ndarrayであるresultに対して10行目でresult[i,:]を実行しています.これはスライスと呼ばれるものでnumpyの非常に重要な機能の一つです.後ほど詳細は説明しますが,ここではresultの行iのみを切り出しているということだと理解して下さい.これをforループですべての行について行っていると考えて下さい.そして,11行目のsavetxtでResult_row_行数.csvというファイル名で各行を.csvで出力しています.このようにしてパラメータを反映したフォルダに異なる名前のファイルを保存できます.
続いては,フォルダ名に実行時間を反映する例です.これにはdatetimeモジュールを使います.基本的な呼び出しはimport datetimeでOKです.基本的なオブジェクトは以下の4つです.これらに新たなオブジェクトを付与することでさらに詳細な命令を下します.
datetime.datetime:日付+時刻 datetime.date:日付 datetime.time:時刻 datetime.timedelta:時間差・経過時間
datetime.datetime.now()は現在の時間情報というものオブジェクトを意味しています.これに様々な情報が格納されています.今回はこのオブジェクトをdtとしています.従って,このdtの型はオブジェクトを示すclassとなっています.これに.yearを付記すれば,dtの年は?という質問をしていることになります.
次に,これを文字列に変換し,保存ファイル名に反映させます.日時を文字列に変換するにはdatetimeオブジェクトに対して.strftime()メソッドを指定します.ここでは,先程dtオブジェクトから0埋めした西暦,月,日,時,分のデータを取得します.これらのデータを文字列にするには(“%”)という記法が必要になります.この%をディレクティブと言います.datetimeのディレクティブは
公式ドキュメント
にすべて記載されています.
%y:下2桁の西暦 %m:0埋めの月 %d:0埋めの日 %H:24h表記の時間 %M:0埋めの分 %Y:4桁の西暦
これにより,time_nowという変数は(西暦-月-日 時間:分,秒)という情報が入った文字列になっています.これをnp.savetxtのファイル名に含めればいいのです.早速,先程のos_parameter_folder.pyにdatetimeを加えてみましょう.ちなみに:はファイルネームとしては無効なので気をつけましょう.こうすれば同じ分で無い限りは実行毎に別々のフォルダ名が生成されます.
os_parameter_folder_datetime.py
- import os
- import numpy as np
- from datetime import datetime
-
- dt = datetime.now()
- time_now = dt.strftime(“(%Y-%m-%d %H%M)”)
- row = 5
- colum = 10
- result = np.random.randint(0,10,(row,colum))
- dir = str(row)+”_”+str(colum)+”_”+time_now #add current time to a new directory name
- os.mkdir("./temp"+dir)
- os.chdir("./temp"+dir)
- for i in range(row):
- out = result[i,:]
- np.savetxt(“Result_row_”+str(i)+”.csv”, out, delimiter =”,”)
-
コラム7.mkdirとmakedirs
本節ではos.mkdirを紹介しましたが,os.makedirsという関数もあります.実際はこちらの使用が推奨されるかも知れません.理由の1つ目はos.mkdirがUnix環境で動作しないことです.2つ目はos.makedirs(exist_ok=True)とすることでフォルダの重複を許すことが出来るからです.