Python実装において役立つ工夫まとめ|非技術者のための業務効率化 #3

f:id:lib-arts:20200210214131p:plain

当シリーズでは非技術者向けに知っておくと役に立つ技術系の知識についてまとめていきます。
#1では業務効率化にあたっての基本的な考え方を抑えたのちにPythonSQLの導入について、#2ではPythonSQLの基本的な内容の演習について取り扱いました。

#3ではPython実装において役立つ工夫をまとめていきます。
以下目次になります。
1. 処理経過の確認
2. 出力ディレクトリの管理
3. tryとexceptを用いたエラー管理
4. まとめ


1. 処理経過の確認
1節では処理経過の確認について取り扱います。

for i in range(1000):
    メイン処理
    if i%100==0:
        経過を確認したい処理をここに書く

基本的な実装パターンとしては上記です。長い処理を回す際は時間がかかるため、経過を確認したり途中経過を出力したい場合があります。この際にfor文のインデックスを10や100などで割り切れるかどうかの条件式を書くことで、途中経過を時折確認することができます。
実装のパターンについては抑えたので、以下では1から100までの和を計算するにあたって具体的に処理経過の確認を行なってみます。

sum_number = 0
for i in range(100):
    number = i+1
    sum_number = sum_number + number
    if number%10==0:
        print("Sum of 1~"+str(number)+":"+str(sum_number))
print("=====")
print(sum_number)

上記の実行結果は下記のようになります。

f:id:lib-arts:20200210220120p:plain

このプログラムでは1から100までの和を計算しているのですが、途中経過も少し確認したいという時があると思います。とはいえ全ての途中の計算経過を可視化するとなると、100行出力されてしまい非常に見にくくなります。こんな際に10ステップ単位、100ステップ単位で経過の出力の処理を記述できると途中経過の確認が非常にしやすくなります。
さらに、この書き方が大きな効果を発揮するのが一つ一つの処理に時間がかかり、数時間単位で処理を回すなどの時です。この際に処理の経過の確認やバグがないかを途中出力を見ることである程度先に把握することができます。
また、処理が途中で止まる際にも役に立ち、読み込んだデータのどこでエラーが出ているのかを発見するのにも役に立ちます。このようにちょっとした工夫をするだけで、作業効率を大幅に向上させることが可能になります。

 

2. 出力ディレクトリの管理
2節では出力ディレクトリの管理について取り扱います。プログラミング処理の結果を出力してcsvのような表型の形式やpngのような画像形式で保存するというのはよくあると思います。その際に把握しておくと良いのが出力ディレクトリの管理です。
この際に考慮すべき点として、『過去の出力ディレクトリを上書きするかどうか』というのがあります。まず上書きする場合は処理を始める前にディレクトリを消去し、もう一度作成するなどの処理を行います。

import os
import shutil

if os.path.exists("./results/"):
    shutil.rmtree("./results/")
os.mkdir("./results/")

上書きする際は上記のような処理を記述することで上書きを実現できます。os.path.existsは指定したパスが存在するかの確認を行い、存在した場合はshutil.rmtreeでディレクトリを中身ごと消去を行います。その後にos.mkdirで同様のディレクトリを作成し、再度スクリプトを実行し結果を出力します。このように上書きを行う際のメリットとしては処理結果が重複しないで済むという点です。一方でデメリットとしては、過去の結果を誤って消してしまう可能性があることです。

import datetime
import os

if not os.path.exists("./results/"):
    os.mkdir("./results/")
time_now = datetime.datetime.now()
dir_path = "./results/"+str(time_now)+"/"
os.mkdir(dir_path)

過去ディレクトリを上書きしない方法としては上記のように日時を用いてディレクトリの名前をつけるなどの方法があります。こちらを用いることでフォルダ(ディレクトリ)名が重複せず、次々と保存していくことができます。こちらのメリットとしては過去の出力結果を消去しなくて済む点、デメリットは出力結果が重複していく点です。

上書きを行うかどうかの判断基準として必要なのは、「処理速度」と「出力結果のデータサイズ」です。処理に時間にかかる方が再計算のコストが大きいためなるべく上書きよりも別ディレクトリに保存の方が安心です。一方でデータサイズが大きい際は、ディレクトリが増えることでマシンの容量が一杯になってしまう可能性もあります。たとえば画像などの出力の際は、データサイズが大きくなりがちなのでディレクトリを上書きする方が望ましいと思います。


3. tryとexceptを用いたエラー管理
3節ではtryとexceptを用いたエラー管理について取り扱います。システムの開発という目線だと、エラーをなるべく起こさないように気を配る必要が大きいですが、ちょっとした業務効率化のためのスクリプトの実行にあたっては、エラーの原因を突き止めることよりも、「とにかく最後まで実行すること」と「エラーが生じている行のデータだけ特定する」という方が優先度が高い場合もあります。
この際にとにかく最後まで処理を回すのとエラー箇所だけ把握するにあたって、tryとexceptを用いると便利です。

for i, row_data in enumerate(data):
    try:
        90%〜99%は動く処理処理
    except:
        print(i)

ここで用いているenumerateはfor文を配列について回す際に、同時にindexも作成してくれるのでなかなか便利な関数です。
上記のような処理を書くことで、とにかく最後まで実行しつつエラー箇所を特定できるので非常に便利です。とにかく先に結果を出して簡単な報告や期待値のすり合わせだけしておきたい際などにこちらは利用すると良いです。


4. まとめ
#3ではPython実装において役立つ工夫をまとめました。どれも最初の学習時にはあまり出てこないトピックですが、利用シーンが多いので抑えておくと良いと思います。