Python の Numpy を使った配列は、機械学習や科学技術計算に不可欠なものです。そして、それらを行うには、配列の要素の値をスムーズに操作できるようになっておくと、より良いでしょう。
そこで、ここでは、Python の配列の操作に関して、
- 配列の要素を確認・変更する方法
- 配列の要素をスライスする方法
- 配列の要素を取り出す方法
- 配列の様子を条件をつけて抽出する方法
- 配列をソートする方法
を解説していきます。
1. 配列の要素の値の確認と変更
まずは、配列の要素の値を確認する方法と変更する方法を見ていきましょう。一次元配列と二次元配列の場合で解説していきます。
1.1. 一次元配列の要素の確認と変更
一次元配列では、要素の値を確認したり変更したりする方法は、リストの場合と全く同じです(参考「Pythonのリストのスライスと分割の方法まとめ」)。
早速見ていきましょう。
まずは、次の一次元配列を作ります。
import numpy as np
array1 = np.array([1, 2, 3, 4, 5])
1.1.1. 要素の確認
確認したい要素のインデックス番号をブラケット [] で指定すると、値を確認することができます。
array1[0] #先頭の要素を確認します。
array1[1] #2番目の要素を確認します。
array1[-1] #最後の要素を確認します。
1.1.2. 要素の値の変更
代入演算子 ( = ) を使って、指定の位置の要素の値を、別のものに変更することができます。
'''配列の要素の値を変更します。'''
array1[0] = 10
array1
1.2. 多次元配列の要素の確認と変更
多次元配列の要素を参照する場合も、「配列[位置][位置]」 で指定しますが、配列は、「配列 [行, 列]」とより直感的に分かりやすく指定することができます。
例として、次の二次元配列から要素を参照してみましょう。
import numpy as np
array2 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]).reshape(3, 3)
print(array2)
上記コードの reshape() メソッドについては「PythonでNumPyのarray使って配列を作る方法まとめ」で解説しているのでご確認ください。
1.2.1. 要素の値の確認
array2[0, 0] # 一行目の一列目
array2[1, 0] # 二行目の一列目
array2[1, 1] #二行目の二列目
array2[2, -1] # 三行目の最後の列
1.2.2. 要素の値の変更
一次元配列の時と同じく、代入演算子 ( = ) を使って、指定の位置の要素の値を、別のものに変更することができます。
array2[0, 0] = 5
array2[1, 0] = 8
array2[1, 1] = 0
print(array2)
簡単ですね。
ただし、注意点として、reshape() メソッドを使って、一次元配列 A から 二次元配列 B を作ったような場合、配列 B の要素の値を変更すると、元の配列 A の値も変更されてしまうことを覚えておきましょう。
import numpy as np
array_a = np.array([1, 2, 3, 4])
array_b = array_a.reshape(2, 2)
'''配列 B の要素の値を変更します。'''
array_b[0, 0] = 9
'''元の配列 A も変更されてしまいます。'''
print(array_a)
print(array_b)
これを見ると、配列 A と配列 B は同一オブジェクトのように思えるのですが、 is 演算子で確認してみると、同一オブジェクトというわけではありません。
'''ただし、A と B が同一のオブジェクトというわけではありません。'''
array_a is array_b
このような予期せぬ変更を防ぐには、reshape() メソッドの乱用を控えるか、オブジェクト指向プログラミングを学習すると良いでしょう。
2. 配列のスライス
次にスライスについても見ていきましょう。これもリストの場合と同じです(参照「Pythonのリストのスライスと分割の方法まとめ」)。スライスする範囲を [開始位置 : 終了位置 : ステップ] で指定します。
2.1. 一次元配列のスライス
まず、次の一次元配列を作ります。
import numpy as np
array = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
一次元配列の場合は、リストと全く同じですが、復習がわりに見てみましょう。
array[:] # 全ての要素を取り出す。
array[:4] # 最初からインデックス番号 3 まで。
array[2 : 8] # インデックス番号 2 から 7 まで。
array[::2] # 先頭から 1 個飛ばしで。
array[::-1] # 全ての要素を逆順に。
2.2. 二次元配列のスライス
二次元配列の場合は、[行のスライス指定, 列のスライス指定] というように、行と列のスライス指定をカンマ区切りで行います。
次の多次元リストを例にみていきましょう。
import numpy as np
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(array)
以下に、いくつかのスライス例を載せていきます。
array[2] # 3 行目
array[:, 2] # 3 列目
array[0, 1] # 1 行目の 2 列目
array[1:, 1:] # 2 行目以降 の 2 列目以降
array[:, 1:] # 全ての行の 2 列目以降
最初は戸惑うと思います。実際に、自分で二次元配列を作って、何度もスライシングを練習して身につけていきましょう。
2.3. スライスと同時に要素を型変換する
既存の配列をスライスして新しい配列を作る時に、要素を型変換したい場合があります。その時は、astype() 関数を使います。
次の二次元配列を例に解説します。
import numpy as np
array = np.array([[1.2, 3.4, 4.5], [5.6, 6.7, 7.8]])
print(array)
ここから、全ての行の 2 列目以降の要素の値を整数に変換して、新たな配列を作ります。
'''全ての行の 2 列目以降を int(整数)型に型変換してスライスします。'''
array2 = array[:, 1:].astype(int)
print(array2)
3. 配列の要素の取り出し
続いて、配列から要素を取り出す方法を見ていきます。
3.1. 一次元配列から要素を順に取り出す
全ての要素を取り出したい場合は、リストと同じように for 文を利用することができます(参照「Pythonのリストからの要素の取り出し方法のまとめ」)。
以下をご覧ください。
import numpy as np
array = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
for i in array:
print(i)
enumerate() 関数を組み合わせると、数え番号をつけながら、要素を取り出すことができます。これはリストでも同様に利用できます。
array_words = np.array(["apple", "banana", "cherry", "durian", "eggplant"])
'''enumerate() 関数で繰り返し番号をつけます。'''
for i, item in enumerate(array_words, 1):
print(i, item)
3.2. 多次元配列から要素を順に取り出す
多次元リストからも for 文を使って要素を取り出すことができます。まず、通常の for 文を書くと、次のように行ごとに取り出されます。
import numpy as np
array = ([[1, 2, 3], [4, 5, 6],[7, 8, 9]])
for i in array:
print(i)
多次元配列の場合は、要素を順番に取り出したいなら、numpy ライブラリの ndenumerate() 関数を使います。この関数を使うと、要素の値を順に取り出すと同時に、その値が配列の中のどこにあるのかを(行, 列)で出力します。
次のコードをご覧ください。
for i, item in np.ndenumerate(array):
print(i, item) # i にはその要素の位置が(行, 列)で、itemには要素の値が入ります。
4. 配列の要素を条件をつけて抽出
ここでは、配列の要素の中から、条件に合うものを抽出する方法を見ていきます。次の配列を使って解説していきます。
import numpy as np
array = np.array([4, 2, 7, 9, 2, 4, 6, 7, 4, 2, 1, 8, 6, 5, 3, 8])
4.1. 条件に合う要素を抽出する
まず、以下のように、ブラケット [] の中で比較演算子を使って、取り出す要素の条件を指定することができます。
array[array >= 5] # 5 以上の値を抽出します。
次のように書くと、偶数のみ、奇数のみを抽出することができます。
array[array % 2 == 0] #偶数の値を抽出します。
array[array % 2 ==1] #奇数の値を抽出します。
多次元配列から抽出する場合も違いはありません。
'''多次元配列でも同様です。'''
array2 = array.reshape(4, 4) # 4行 × 4列の二次元配列を作ります。
array2[array2 > 5] # 5 より大きな値を抽出します。
論理式を組み合わせると、さらに細かい条件を作ることができます。なお、論理式は、and, or, not ではなく、
- 論理積:&
- 論理和:|
- 論理否定:~
を使います。これらは「Pythonの演算子の一覧表とわかりやすい解説」でご確認ください。
それでは見ていきましょう。
'''論理式を組み合わせる時は、&, |, ~ を使う。'''
array[(array % 2 == 0) & (array >=5)] # 論理積。偶数で 5 以上の値を抽出します。
array[(array % 2 == 0) | (array >=8)] #論理和。偶数か 8 以上の数値を抽出します。
array[~(array % 2 ==0)] #論理否定。偶数でない値を抽出します。
4.2. 条件に合う要素の値を変更する
条件に合う要素を抽出するだけでなく、その値を変更することができます。次の例をご覧ください。元の配列から、偶数は 0 に奇数は 1 に変更しています。
import numpy as np
array = np.array([4, 2, 7, 9, 2, 4, 6, 7, 4, 2, 1, 8, 6, 5, 3, 8]).reshape(4, 4)
array[array % 2 == 0] = 0 # 偶数を一括で 0 に変更
array[array % 2 == 1] = 1 # 奇数を一括で 1 に変更
print(array)
5. 配列のソート
配列の要素をソートするには、numpy.ndarray オブジェクトで使える sort() メソッド、または numpy ライブラリの sort() 関数を使います。
メソッドは既存の配列そのものを並び替えるのに対し、関数は新しい配列を作ります。
5.1. sort() メソッドでソートする
まずはメソッドを使った方法から見ていきましょう。
import numpy as np
array = np.array([3, 5, 1, 6, 9, 2, 7, 4, 1, 5, 6, 8, 3, 9])
array.sort() # sort() メソッドでソートします。
array
このように、元の配列が並び替えられていることをご確認ください。
なお、numpy.ndarray オブジェクトの sort() メソッドは、並び替えの基準はリストオブジェクトの sort() メソッドと同じですが、reverse オプションはありません(参照「Pythonのリストをソートする方法まとめ」)。そのため、要素を降順にした配列を作るには、次の sort() 関数を使います。
5.2. sort() 関数でソートする
numpy ライブラリの sort() 関数の引数には、配列だけではなく、リストやタプルを渡すこともできます。それでは見ていきましょう。
import numpy as np
array = np.sort([3, 6, 7, 1, 2, 5, 4])
array
このように要素を並び替えた新しい配列を作ることができます。今回は、引数をリストにしましたが、ここが配列でも構いません。
これを降順に並び替えるには、関数の後に続けて、スライスを指定します。
'''降順に並び替えた配列を作るには、ソートした配列を逆順にスライスします・'''
array2 = np.sort(array)[::-1] #ソート関数の後に続けてスライスを指定します。
array2
6. まとめ
一次元配列の場合は、配列の操作は、リストと非常に似通っています。多次元配列の操作も、行や列や奥行きで指定するので、多次元リストよりは直感的に分かりやすく感じられるでしょう。
ただし、配列で扱うメソッドや関数は、numpy ライブラリのものなので、Python の組み込み関数などと比べると、少し違いがあります。
実際に、手を動かして慣れていきましょう。
コメント