NumPy
前回、PythonのNumPyでnp.convolveのmode(same、full、valid)を比較した結果を紹介しました。
今回はNumPyで2つのリスト間で1つのリストを条件の判定、その判定結果を使ってもう1つのリストの要素の書き換えをする方法(+Pandasでのやり方)を紹介します。
なかなかイメージしづらいと思うので、例えのプログラムを作成してみました。
a_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b_list = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
for i in range(len(a_list)):
if a_list[i] <= 3:
b_list[i] = 0
elif a_list[i] > 7:
b_list[i] = 100
print(b_list)
実行結果
[0, 0, 0, 40, 50, 60, 70, 100, 100, 100]
a_listには1から10までの数字が、b_listには10から100まで10刻みの数字が格納されています。
そしてa_listの数字が3以下の場合にはb_listの同じインデックスの要素を0に、a_listの数字が3より大きくて7以下の場合はb_listの同じインデックスの要素はそのままに、a_listの数字が7より大きい場合はb_listの同じインデックスの要素を100に書き換えるというものです。
それでは始めていきましょう。
NumPyで実装
この2つのリスト間で一つのリストを条件の判定、その判定結果を使って要素の書き換えをすることを、これまでどういった時に使ったかというとフーリエ変換で逆フーリエ変換をする際にバンドパスフィルタ(ローパスフィルタやハイパスフィルタ)を実装する際に用いました。
その際こんな書き方をしていました。
b_list[a_list 判定式] = 書き換える値
「a_list 判定式」は例えば「a_list <= 3」というような判定式です。
適当な数字で試してみます。
import numpy as np
a_list = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
b_list = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
b_list[(a_list <= 3)] = 0
b_list[(a_list > 7)] = 100
print(b_list)
実行結果
[ 0 0 0 40 50 60 70 100 100 100]
先ほどのfor文を使った書き方よりも簡素に書くことができ、ちゃんとa_listで3以下となるインデックスのb_listの要素が0に、a_listで7以上となるインデックスのb_listの要素が100になっています。
なんでこんなふうになるのか分からずに使っていたので、とりあえず分解して、「b_list[(a_list <= 3)]」の「a_list <= 3」の部分と「b_list[(a_list > 7)]」の「a_list > 7」の部分のみ試してみました。
import numpy as np
a_list = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
b_list = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
print(a_list <= 3)
print(a_list > 7)
実行結果
[ True True True False False False False False False False]
[False False False False False False False True True True]
実はこの判定式だけでbool値のリストが得られていました。
そして「b_list[(a_list <= 3)] = 0」とするとそのbool値のリストで「True」のところが最後の「= 0」で書かれた値に書き換えられるというわけです。
import numpy as np
a_list = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
b_list = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
tf1 = a_list <= 3
tf2 = a_list > 7
b_list[tf1] = 0
b_list[tf2] = 100
print(b_list)
実行結果
[ 0 0 0 40 50 60 70 100 100 100]
ということで一つの式で条件式として判定し、bool値のリストとして、「True」となったところの値を書き換えるということをしているようです。
逆フーリエ変換の時に特有の書き方なのかなぁと思っていたので、こんな使い方があるとは目から鱗でした。
ちなみに何も解説せずに「NumPyのndarray」に変換していますが、通常のリストだとこのように判定式だけでbool値のリストとはならずエラーとなるので注意です。
import numpy as np
a_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b_list = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
print(a_list <= 3)
print(a_list > 7)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 6
3 a_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
4 b_list = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
----> 6 print(a_list <= 3)
7 print(a_list > 7)
TypeError: '<=' not supported between instances of 'list' and 'int'
Pandasでの実装
NumPyでのやり方は知りませんでしたが、実はPandasでのやり方は知っていました
df["B"][df["A"] 判定式] = 書き換える値
先ほどの例で試してみるとこんな感じです。
import numpy as np
import pandas as pd
a_list = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
b_list = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
df = pd.DataFrame()
df["a"] = a_list
df["b"] = b_list
print(df)
df["b"][df["a"] <= 3] = 0
df["b"][df["a"] > 7] = 100
print(df)
実行結果
a b
0 1 10
1 2 20
2 3 30
3 4 40
4 5 50
5 6 60
6 7 70
7 8 80
8 9 90
9 10 100
a b
0 1 0
1 2 0
2 3 0
3 4 40
4 5 50
5 6 60
6 7 70
7 8 100
8 9 100
9 10 100
実はPandasもNumPyと同じように判定式だけでbool値のリストを作成し、その判定がTrueとなるところを書き換えるという同じ原理のものでした。
import numpy as np
import pandas as pd
a_list = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
b_list = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
df = pd.DataFrame()
df["a"] = a_list
df["b"] = b_list
print(df)
print(df["a"] <= 3)
print(df["a"] > 7)
実行結果
a b
0 1 10
1 2 20
2 3 30
3 4 40
4 5 50
5 6 60
6 7 70
7 8 80
8 9 90
9 10 100
0 True
1 True
2 True
3 False
4 False
5 False
6 False
7 False
8 False
9 False
Name: a, dtype: bool
0 False
1 False
2 False
3 False
4 False
5 False
6 False
7 True
8 True
9 True
Name: a, dtype: bool
PandasはNumPyと依存関係があるというのがよく分かる類似点だなぁなんて思いました。
次回はPythonのmatplotlibで散布図「plt.scatter」を使う際、それぞれの点の色を変える方法を紹介します。
ではでは今回はこんな感じで。
コメント