【内包表記の使い方】forループを1文で記述できる方法を解説|Python

Python [文法解説]

内包表記の基本構造

まずは、内包表記の基本構造について簡単に解説します。

ここでは理解しやすいように、forループの記述方法と比較します。

まずはforループの記述方法ですが、

forループ

for 変数 in リスト:
変数を使用した式

のように記述しますね。

一方で内包表記の場合、

内包表記

[変数を使用した式 for 変数 in リスト]

のように記述できます。

1文で記述できるので、内包表記で記述した方がすっきりした印象を受けますね。

内包表記の具体例

内包表記の記述パターンは1つではないので、以降では具体例を紹介します。

(1) 一般的な場合(1変数・if・if else無し)

a = [x * 5 for x in [0, 1, 2]]

こちらは、先ほどの紹介した内包表記の基本構造と全く同じ形です。

処理内容としては、[0, 1, 2]というリストの各要素を5倍にするという、簡単な処理です。

print(a)
>>>[0, 5, 10]

出力結果を確認すると、[0 ,1 ,2]の各要素がそれぞれ5倍になっていることが分かります。

(2) ifを使用する場合

a = [x * 5 for x in [0, 1, 2] if x >= 1]

こちらの処理内容としては、基本的には先ほどと同様に[0, 1, 2]のリストの各要素を5倍にする処理ですが、末尾にif文がつくことによって、リストの要素が1以上の場合にx*5を計算します。

print(a)
>>>[5, 10]

出力内容を確認すると、1*5、2*5のみが計算されていて0*5は計算されていないことが分かります。

【補足】forループを使用した場合

ちなみにこの処理をforループで記述すると、下記のようになります。

a = []
for x in [0, 1, 2]:
    if x >= 1:
        a += [x * 5]
ねずみくん
ねずみくん

forループだと4行必要なところが、内包表記を使用すると1行で済むのは便利ですね!

(3) if elseを使用する場合

a = [x * 5 if x >= 1 else '〇' for x in [0, 1, 2]]

こちらの処理内容としては、リストの要素が1以上の場合は5を掛け、それ以外の場合は文字列’〇’となります。

先ほどの「(2) ifを使用する場合」とは異なり、ifの位置が計算式の直後になることに注意してください。

print(a)
>>>['〇', 5, 10]

出力結果を確認すると、リストの要素が1より小さい場合(0の場合)は、’〇’となっています。

【補足】forループを使用した場合

ちなみにこの処理をforループで記述すると、下記のようになります。

a = []
for x in [0, 1, 2]:
    if x >= 1:
        a += [x * 5]
    else:
        a += '〇'
ねずみくん
ねずみくん

なんと、今度は6行のコードが1行に集約できました!

(4) 複数変数を使用する場合

a = [x * 5 + y for x, y in zip([0, 1, 2], [3, 4, 5])]

この場合はforループと同様に、zip()関数を使用します。

print(a)
>>>[3, 9, 15]

出力結果を確認すると、各要素が下記のように計算されていることが分かります。
 ・0 * 5 + 3 = 3
 ・1 * 5 + 4 = 9
 ・2 * 5 + 5 = 15

【補足】forループを使用した場合

ちなみに、この処理をforループで記述すると、下記のようになります。

a = []
for x in zip([0, 1, 2], [3, 4, 5]:
    a += [x * 5 + y]

(5) 2つのループを使用する場合

a = [x * 5 + y for x in [0, 1, 2] for y in [3, 4, 5]]

1つ目の「for 変数 in リスト」の後ろに、さらに「for 変数 in リスト」を記述します。

この場合、前に記述したものが外側のループになり、後に記述したものが内側のループとなります。

print(a)
>>>[3, 4, 5, 8, 9, 10, 13, 14, 15]

出力結果を確認すると、下記のように処理されていることが分かります。
 ・0 * 5 + 3 = 3
 ・0 * 5 + 4 = 4
 ・0 * 5 + 5 = 5
 ・1 * 5 + 3 = 8
 ・1 * 5 + 4 = 9
 ・1 * 5 + 5 = 10
 ・2 * 5 + 3 = 13
 ・2 * 5 + 4 = 14
 ・2 * 5 + 5 = 15

【補足】forループを使用した場合

ちなみに、この処理をforループで記述すると下記のようになります。

a = []
for x in [0, 1, 2]:
    for y in [3, 4, 5]:
        a += [x * 5 + y]

内包表記を使用するメリット

続いて、内包表記を使用するメリットを紹介します。

恐らくforループの方が理解しやすいと思う方も多いと思いますが、以降で紹介する理由から内包表記を使用することをおすすめします!

①簡潔にコードを書ける

これまで紹介してきた具体例で一目瞭然化と思いますが、最初に紹介するメリットは「簡潔にコードを書ける」ことです。

内包表記を使用することで記述するコードの量が減るのですが、これによって下記のメリットがあります。

記述するコードの量が減ることで得られるメリット
  • コーディングが速くなる
  • コード修正が楽になる

私が特に大きいと感じているのが、2つ目のメリットです。

内包表記を記述することで、本来数行(多い場合は10行を超える場合もありますが)必要とするコードを1行にまとめることができるので、後からコードをチェックする際に見るべきレコード件数が大きく減ります。

このことで、後から修正する・コードを追加するとなった際に、どの箇所に手を加えればよいのかの判断がつきやすくなります。

②処理が速い

2つ目のメリットは、forループを使用する場合よりも処理が速く完了することです。

場合によっては、forループでは10分かかる処理であっても内包表記を使用すると、数秒で完了することもあります。

扱うデータのサイズが小さい場合はあまり気にならないかと思いますが、サイズが大きい場合は少しの違いが大きな差になるので、日頃から内包表記を使用して慣れていた方がよいですよ!

実際に比較してみると…

【スクレイピング】学習データ(netkeibaから取得したレースデータ)を加工」で出てくる処理の処理時間を、内包表記とforループで比較してみます。

下記で出てくる変数「df」は、DataFrame型の変数でレコード件数は327,759です。

import datetime

start = datetime.datetime.now()
df['weight'] = [int(str(x).split('(')[0]) for x in df['馬体重(増減)']]
end = datetime.datetime.now()
print(str(end - start))

>>>0:00:00.465038
import datetime

start = datetime.datetime.now()
a = []
for x in df['馬体重(増減)']:
    a += [int(str(x).split('(')[0])]
df['weight'] = a
end = datetime.datetime.now()
print(str(end - start))

>>>0:00:00.530848

この処理ではあまり差はありませんでしたが、それでもやはり内包表記の方が早く処理が完了していることが分かります。

他の記事(Qiita)でも内包表記とforループの処理速度比較されていますが、内包表記を使用することで処理時間が約半分に短縮されていることが確認されています。

慣れれば簡単に書けるようになるので、日頃から意識して使うことをおすすめします!

処理速度向上に貢献する関数

内包表記の他に処理速度向上に貢献する関数として「appy関数」・「map関数」が挙げられます。

各関数を簡単に説明すると、

  • apply関数:
     →Pandas DataFrameを行・列毎に任意の処理を一括で行う
  • map関数:
     →Pandas Serieseまたはリスト型

となります。

詳細については以下のページで解説しているので、気になる方は是非読んでください!

コメント

タイトルとURLをコピーしました