map関数
前回、datetimeのNanであるNaT(Not-a-Time)とnumpyとPandasにおけるNaTの判定を解説しました。
今回はリストで関数を実行できるmap関数を紹介します。
例えばこのプログラムのように、rangeで取得したリストの要素に対して、自己関数squareで二乗して、その結果をリストval_listに格納するという処理があったとします。
initial_list = range(10)
def square(i):
sq = i * i
return sq
result_list = []
for i in initial_list:
result_list.append(square(i))
print(result_list)
実行結果
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
この場合、initial_listから一つづつ要素を取り出して、関数squareで処理する必要があるため、for文を使います。
ただ今回紹介するmap関数を使うとfor文を使わずに同じプログラムを書けるようになります。
それでは始めていきましょう。
map関数の基礎と返り値の取得
まずはmap関数の使い方を見ていきます。
map関数は「map(関数, 関数の引数のリスト)」として使用します。
initial_list = range(10)
def square(i):
sq = i * i
return sq
result_map = map(square, i_list)
print(result_map)
実行結果
<map object at 0x107318340>
これでmap関数は実行できたものの、返ってきた値がマップオブジェクトとなっており、そのままでは使用することができません。
このような場合は結果を「list(マップオブジェクト)」としてリストに変換してあげます。
initial_list = range(10)
def square(i):
sq = i * i
return sq
result_map = map(square, i_list)
print(list(result_map))
実行結果
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
関数が複数の引数を使用する場合
map関数で使用する関数の引数が複数だった場合、「map(関数, 関数の引数のリスト1, 関数の引数のリスト2, 関数の引数のリスト3…)」とすると複数の引数のリストを渡すことができます。
x_list = range(5)
y_list = range(5, 10)
def times(x, y):
times_val = x * y
return times_val
result_map = map(times, x_list, y_list)
print(list(result_map))
実行結果
[0, 6, 14, 24, 36]
ちなみにこの場合、二つの引数のリストは同時に前から処理されていきます。
つまりzip関数を使ってこのように書くこともできます。
x_list = range(5)
y_list = range(5, 15)
def times(x, y):
times_val = x * y
return times_val
result_list = []
for x, y in zip(x_list, y_list):
result_list.append(times(x, y))
print(result_list)
実行結果
[0, 6, 14, 24, 36]
複数の返り値を取得する場合
次は複数の返り値を取得する場合です。
例えば関数がこんな感じの場合、出力される返り値に少し注意が必要です。
def calc(x, y):
sums_val = x + y
times_val = x * y
return sums_val, times_val
先ほどまでの結果をみると、受け渡した引数のリストの順番通りに処理され、そのリスト(マップオブジェクトとはいえ)が返ってくると思いがちです(というか私は思いました…)。
そのためこんなプログラムを書いて、エラーとなることがあります。
x_list = range(5)
y_list = range(5, 15)
def calc(x, y):
sums_val = x + y
times_val = x * y
return sums_val, times_val
sums_map, times_map = map(calc, x_list, y_list)
print(list(sums_map))
print(list(times_map))
実行結果
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [16], in <cell line: 9>()
6 times_val = x * y
7 return sums_val, times_val
----> 9 sums_map, times_map = map(calc, x_list, y_list)
11 print(list(sums_map))
12 print(list(times_map))
ValueError: too many values to unpack (expected 2)
要するに上記の例では関数の返り値が「sums_val」と「times_val」があるのですが、それぞれの結果のリスト、つまり「5, 7, 9, 11, 13」と「0, 6, 14, 24, 36」という二つのリストが返ってくると思ってしまったわけです。
実際はそうではなくて、受け渡した引数のリストの前から順に処理されますので、プログラムはこうすべきでした。
x_list = range(5)
y_list = range(5, 15)
def calc(x, y):
sums_val = x + y
times_val = x * y
return (sums_val, times_val)
result_map = map(calc, x_list, y_list)
print(list(result_map))
実行結果
[(5, 0), (7, 6), (9, 14), (11, 24), (13, 36)]
関数の返り値をタプルかリストとしてやり、返り値を一つとしてやるわけです。
こうすると受け渡した引数のリストが前から順番に処理されているのがよく分かります。
この状態では残念ならがそれぞれ「足し算の結果のリスト」、「掛け算の結果のリスト」となっていないので、この後もう一工夫必要です。
単純には関数を「足し算の関数」と「掛け算の関数」と分けてしまうのがいいように思えます。
まぁそこら辺はまた別のお話ということで。
次回はnumpyのリスト(アレイ)に要素を追加するnp.appendに関してちょっと検討してみます。
ではでは今回はこんな感じで。
コメント