2次元配列の列を取り出す方法のいろいろ.
import
import numpy as np
配列の生成
まずは適当に5x4の配列を生成
a = np.arange(5*4).reshape([5, 4])
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]
# [12 13 14 15]
# [16 17 18 19]]
特定の1列を抽出する
# 2列目のみ
b = a[:, 2]
print(b)
# [ 2 6 10 14 18]
a[row, column]
とすると, row
の部分で行の指定, column
の部分で列の指定を行う.
今回は列を取り出したいので, row
の部分は常に:
とする. :
のみ記述することで, 行に関しては特に指定しないという意味になる. つまりa[:, 2]
は, 「すべての行から, インデックスが2の要素だけください」ということになる.
連続する複数の列を抽出する
1, 2列目や0~2列目など, 連続する複数の列を取り出す.
# 1, 2列目
b = a[:, 1:3]
print(b)
# [[ 1 2]
# [ 5 6]
# [ 9 10]
# [13 14]
# [17 18]]
1:3
は1以上3未満を意味するため, 1~2列目が取り出せる.
1:
や:3
のように指定すれば, 1列目以上や3列目未満の列がすべて取得できる.
# 1列目~
b = a[:, 1:]
print(b)
# [[ 1 2 3]
# [ 5 6 7]
# [ 9 10 11]
# [13 14 15]
# [17 18 19]]
# 0~2列目
b = a[:, :3]
print(b)
# [[ 0 1 2]
# [ 4 5 6]
# [ 8 9 10]
# [12 13 14]
# [16 17 18]]
偶数列, 奇数列など
# 4x8の配列を生成
a = np.arange(4*8).reshape([4, 8])
# [[ 0 1 2 3 4 5 6 7]
# [ 8 9 10 11 12 13 14 15]
# [16 17 18 19 20 21 22 23]
# [24 25 26 27 28 29 30 31]]
# 偶数列
b = a[:, ::2]
print(b)
# [[ 0 2 4 6]
# [ 8 10 12 14]
# [16 18 20 22]
# [24 26 28 30]]
# 奇数列
b = a[:, 1::2]
print(b)
# [[ 1 3 5 7]
# [ 9 11 13 15]
# [17 19 21 23]
# [25 27 29 31]]
このように, 基本的にリストの操作方法に則っているため, 倍数や逆順での取得も可能.
# 後ろから3の倍数の列
b = a[:, ::-3]
print(b)
# [[ 7 4 1]
# [15 12 9]
# [23 20 17]
# [31 28 25]]
# 1列目以上7列目未満の一列飛ばし
b = a[:, 1:7:2]
print(b)
# [[ 1 3 5]
# [ 9 11 13]
# [17 19 21]
# [25 27 29]]
不規則に複数の列を抽出する
個人的にはここからが本題.
1, 5, 6列などのように, 不規則に列を取り出したいときがある.
ひと手間増えるが, 列の数と同じ長さのフィルターを用意することで実現できる.
# インデックス1, 5, 6の値がTrue, それ以外がFalseの長さ8のリスト
f = [False, True, False, False, False, True, True, False]
b = a[:, f]
print(b)
# [[ 1 5 6]
# [ 9 13 14]
# [17 21 22]
# [25 29 30]]
# boolean型の1x8の零行列を生成して, 欲しい列のインデックスの値だけTrueに変えるパターン
f = np.zeros(8, dtype=bool)
columns = [1, 5, 6]
f[columns] = True
b = a[:, f]
print(b)
# [[ 1 5 6]
# [ 9 13 14]
# [17 21 22]
# [25 29 30]]
# 指定した列以外を取得したい場合はonesですべてTrueの配列を生成し, いらない列だけFalseに変える
f = np.ones(8, dtype=bool)
columns = [1, 5, 6]
f[columns] = False
b = a[:, f]
print(b)
# [[ 0 2 3 4 7]
# [ 8 10 11 12 15]
# [16 18 19 20 23]
# [24 26 27 28 31]]
numpyで扱う配列は列の数が多い場合がほとんどだと思うので, 二つ目の方法がメインになってくると思う.
例ではnp.zeros
を使用しているが, 状況によってはnp.ones
で要素がすべてTrue
の配列を作ってから, いらない列だけFalse
に変える方が楽かもしれない.
※ 2020/07/04に追記
np.zeros
を使う方法よりも簡単な方法をコメントで教えていただいたので, 下に示す.
# 4x8の配列を生成
a = np.arange(4*8).reshape([4, 8])
# [[ 0 1 2 3 4 5 6 7]
# [ 8 9 10 11 12 13 14 15]
# [16 17 18 19 20 21 22 23]
# [24 25 26 27 28 29 30 31]]
# 1, 5, 6列を取り出す
b = a[:, [1, 5, 6]]
print(b)
# [[ 1 5 6]
# [ 9 13 14]
# [17 21 22]
# [25 29 30]]
おわりに
あまり話を広げすぎてもわかりづらいと思い, 今回は列のみに絞って解説したが, 列同様に行も指定することで特定の行の特定の列を取り出すこともできる. 3次元以上の場合もこれらの方法を応用することで, 欲しい要素を抽出できる.
一番最後に解説した零行列を作って列を取り出す方法は, 自分としては結構綺麗にできたと思うけど、他にもっと楽な方法がありそうな気もする.
追記
複数の列を取り出す, よりスマートな方法を@nkayさんにコメントで教えていただいたので, 書き加えた. (July 4, 2020)