注目キーワード

Pythonのループ処理をマスターしよう!

ループ処理無くしてPythonは語れない

Pythonでの繰り返し処理(ループ)は、化学研究者にとって業務自動化や機械学習に欠かせない技術です。
概念から実装まで完璧にマスターしましょう!

本記事では、化学分野での実際の応用をイメージできるように、実例を交えながら解説してきます。
具体的には、スペクトルデータ解析の場面を例にします。
学習を進める中で、ご自身の業務であれば、こういったところにループ処理が適用できそう、といったイメージを膨らませてください!

超重要なループ処理ですが、Pythonはforループwhileループという2種類の繰り返し構造だけです!
大事なのでそれなりのボリュームの記事になりました。
それぞれじっくり解説しているので、ぜひ最後まで手を動かしながら読んでみてください。

基礎文法の全体像については以下の記事を参照ください。

関連記事

研究者のPython活用で必要な8つのポイント はじめに 「プログラミングって難しそう…?」 そう思っている化学者研究者の皆さん、ちょっと待ってください! 化学者研究者がPythonを使いこなすために押さえておくべきポイントは8[…]

ループの概念を理解しよう

まずはループ処理の概念・概略を理解しましょう。
図解すると以下の通りです。

ループ処理はその名の通り、処理ルートがループ構造になっています。

処理対象は「繰り返し可能な、要素が複数あるデータ」です。
具体的にはリストやタプル、辞書などのコンテナ型や、文字列などです。
これらをまとめて「イテラブル」と言ったりします。

要素が複数あるため、図の通り、この要素を順に処理していくのがループ処理です。

ループ処理にはforループとwhileループの2種類あります。
「処理をいつまで繰り返すか」という違いがあり、forループは要素すべてに対して処理するまで続き、whileループは設定した条件を満たす間ずっと処理する、と理解ください。

では次項から、forループとwhileループの詳説に入っていきます。

forループ

forループを理解しよう

化学研究者のPython活用で最もよく使うループはforループです。
forループを使うと、処理がどういう動きをするのか、どんなことができるのか、完璧にマスターしましょう!

forループの構文を図解しました。

forループは「for 変数 in イテラブル:」という宣言でスタートします。
forの後の変数名は任意です(a とか i とか value とかなんでもOK)。
そして in の後に処理したいイテラブルオブジェクトを指定します。

次に改行すると、Jupyter LabなどのIDEを使っている場合は勝手にスペース4つ分のインデントが入ります。
インデントされた状態で、各要素に対して繰り返し行いたい処理内容を書き込みます。
インデントが同じ間はずっとforループの中と認識され、インデントを無くすとforループの外と認識されます。

処理の流れは、「イテラブルの要素が変数に代入 ⇒ 変数に対して書き込まれた処理が実行」が次々起きるイメージです。
イメージしやすいように、簡単なサンプルコードも図に記述しています。
このコードで「1, 4, 9」が出力されます(実際はそれぞれ改行されて出力)が、図説の通り3周のループが実行されています。

どうでしょう。forループ、理解できましたか?

forループを使ってみよう

Pythonに限らず、プログラミングは自分で手を動かさないと中々定着しません
ということで、コードを書いてみましょう。

先ほどのサンプルコードの応用問題です。
リスト[1, 2, 3]の各要素を2乗した値を持つ新たなリストを作成しましょう。
そして、最後に作成したリストを出力してみましょう。

以下にコード例を載せますが、まずは自分で書いてみることをお勧めします!

# 空のリストを定義
list_a = []

# forループの宣言
for x in [1, 2, 3]:
    a = x ** 2
    list_a.append(a)  # 2乗した値をリストに追加

# インデントが無いためforループ外の処理
print(list_a)  # [1, 4, 9]と出力

どうでしょう。自分で書けましたか?

リスト型のメソッドappend()を使用しています。
コンテナ型の扱いに自信がない方は以下の記事を参考にしてみてください。

関連記事

業務自動化と機械学習に必須のリスト操作 Pythonを使った化学研究の自動化や、最近注目を集める機械学習による開発効率化において、コンテナ型(データをまとめて扱う型)の理解は欠かせません。 コンテナ型にはいくつか種類がありますが、特にリ[…]

補足ですが、実は上述のコードは「内包表記」というテクニックを使えば、もっとシンプルに記述することができます。
上の例では、処理コード(コメント行、空白行除く)が4行ですが、内包表記を使えば1行で済みます。
内包表記については別記事でまとめる予定です。

range()関数について

forループとセットで使うことが多いrange()関数に触れておきます。

range()関数は引数で指定した条件に従って、forループで処理できるデータ、つまりイテラブルオブジェクトを生成する関数です。
引数はスライスとよく似た構造をしており、以下のルールがあります。

  1. range(x): 0からx-1までの連番のオブジェクトを返す
  2. range(x,y): xからy-1までの連番のオブジェクトを返す。
  3. range(x,y,z): xからy-1までz刻みのオブジェクトを返す。

実際にコードで見てみましょう。

print('range(x)は0からx-1')
for i in range(4):
    print(i)

print('range(x, y)はxからy-1')
for i in range(2, 5):
    print(i)

print('range(x, y, z)はxからy-1までz刻み')
for i in range(2, 9, 3):
    print(i)

どんな場面で使うのか具体例を挙げてみます。

複数ロットの実験データが別々のリストに格納されているとき、各要素の平均値が欲しいケースを想定してみましょう。
そんな時は以下のようにコードが書けます。

# 3ロット分の実験データ
trial1 = [1.1, 1.2, 1.3]
trial2 = [1.0, 1.3, 1.4]
trial3 = [1.2, 1.1, 1.5]

for i in range(len(trial1)):  # len(trial1) = 3 なのでrange(3) ⇒ 0, 1, 2が順にiに代入
    avg = (trial1[i] + trial2[i] + trial3[i]) / 3  # 同じインデックスの要素の平均を算出
    print(f"{i + 1}番目の測定の平均値 = {avg}")

range(len(リスト))とすることで、変数(i)にリストのインデックスを順に代入できます。
そのため、処理コードの部分でリスト[i]とすることで、リストの要素に順にアクセスできます。

同じ要素数のリストが複数あって、同じインデックスの要素同士に何か処理を加えたいケースに活用できます!

whileループ

whileループを理解しよう

forループに比べると使用頻度は低いですが、こちらもしっかり理解しておきましょう!
forループとの違いを意識すると理解が進みます。

whileループの構文を図解しました。

whileループは「while 条件式:」という宣言でスタートします。
forループと異なり、変数やイテラブルオブジェクトの指定は不要です。

whileループは、条件式を満たす限り処理を繰り返します。
条件式を満たすかどうかの判定は、ループが1周するたびに判定をします。
毎回チェックされる入門ゲートみたいなイメージです!

イメージしやすいように、簡単なサンプルコードも図に記述しています。
まずnumという変数を宣言して、1を代入しています。
そして、「num < 3」という条件でwhileループを開始します。

まずループ1周目です。
最初に条件式の判定です。num = 1なので「num < 3」を満たします。
条件をクリアしたので処理に入ります。
最初の処理はprint(num)なので、単純にnum (=1) が出力。
次に、「num += 1」(「num = num + 1」と同義)という処理でnumが2に更新。

ループ2週目です。
次はnum = 2で、「num < 3」の条件式をクリア。
2が出力され、同様に1加算されてnumが3に更新。

さて、ループ3周目です。
今度はnum = 3で、「num < 3」の条件を満たしません。
この瞬間にループが終了します。
print以降の処理は実行されずに、インデントされていないwhileループの外の処理に移ります

どうでしょう。forループと全然違いますね!
でも、同じようにループ処理になっていますね。

では、このwhileループはどんな時に使うのでしょうか。
forループよりもイメージが湧きづらいので、実例でコードを書いてみましょう。

whileループを使ってみよう

whileループの最大の特徴は「条件を満たす限り繰り返せる」ところです。
これを活用できる場面を2つ紹介します。

  1. ユーザーの入力に応じて繰り返す処理

    パスワード入力が一番わかりやすい例です。
    input()関数でユーザー入力を求める際、「password != ~」という条件式でwhileループを作れば、パスワードが違う限りループさせることができます。
    ユーザーに特定の入力をさせたい時にwhileループは有効です。

    password = ""
    while password != "chem123":
        password = input("パスワードを入力してください: ")
    print("ログイン成功")

  2. 目標値に達するまで繰り返す

    機械学習(特に最急降下法などの最適化アルゴリズム)でもwhileループは利用されます。
    例えば、回帰分析を行うときに「誤差が十分小さくなるまでパラメータ調整を繰り返す」という処理をwhileループで実装できます。
    この場合、「誤差 > 閾値」ような条件式を設定します。
    サンプルコードは少々難易度が高いので、ここでは割愛します。

breakとcontinueによる制御

breakとcontinueとは

さて、ここまでループ処理の基本を解説してきました。
かなり分かってきたのではないでしょうか。

ここで、ループ処理をさらに柔軟に制御する手法を紹介します。
「break」と「continue」です。
「break」は強制的にループを終了したい時、「continue」は強制的にループの先頭に戻したい時に使用します。

これらは条件分岐処理と組み合わせて使用します。
条件分岐処理については別記事で詳説予定です。
今回は条件分岐処理を学習している前提で話を進めます。

「break」と「continue」の使い方を図解しました。

forあるいはwhileループの中で、if式を使って任意の条件を設定します。
そのif式の中でbreakあるいはcontinueと記述します。
すると、breakに達するとループが強制終了し、continueに達すると強制的にループの先頭に戻って次の周回がスタートします。

このように、ある条件が発生した時のループの挙動を変えれるのが特徴です。

breakを使ってみよう

breakは特定の値が出てきたときに処理を止めたり、whileを使った無限ループの終了条件の指定に用います。

前者は異常検知で有効です。以下サンプルコードです。
breakを使うことで、異常値による見当外れな処理値に誤誘導されるのを防げます。

# 測定値に異常(例:ノイズやセンサーエラー)が含まれていたら処理を止める
measurements = [0.99, 1.01, 1.00, 999.9, 1.02]
for value in measurements:
    if value > 10:  # 明らかな異常値
        print("異常値を検出!測定を中止します。")
        break
    print(f"正常値: {value}")
# 最後の1.02は出力されずにfor文が強制終了

 

後者はユーザー入力で有効です。
無限ループとは「while True:」で始まるwhileループのことです。
ある条件を満たすまで無限にループするため、どうなったらループを抜けるか指定する必要があります。

サンプルコードでは「exit」と入力されるまで、無限にループする = 無限にコマンド入力を求めてきます。

while True:
    command = input("コマンドを入力(exitで終了): ")
    if command == "exit":
        print("終了します")
        break
    else:
        print(f"受信: {command}")

 

continueを使ってみよう

continueは特定の条件で処理をスキップしたい時に使用します。
強制的にループ先頭に戻せるので、continueより後の処理をスキップできます。

以下サンプルコードです。
欠損値を含むリストデータにループ処理を行うとき、欠損値に対する処理をスキップできます。
value = Noneのとき、if文の中に入ってcontinueに達すると、強制的にループ先頭に戻って次の周回がスタートするので、print処理がスキップされます

# Noneは測定エラーや未取得データを表す
measurements = [1.02, None, 1.05, 0.98, None, 1.01]
for value in measurements:
    if value is None:
        continue
    print(f"有効な測定値: {value}")

おわりに

いかがでしたか?
ループ処理の基本をギュッと詰め込んだので、なかなかのボリュームだったかと思います。

この記事の内容をマスターできれば、化学研究者のPython活用では困らないレベルになれるので、何度か読み返してみてください!

途中のサンプルコードも自分で書いてみて、実際の動きを理解するようにしてください。
そうすることで、今後の学習も効率的になります。

最新情報をチェックしよう!