HOWTO · NumPy

NumPy 配列から列を取得する方法

2 次元 NumPy 配列から列を選択し、形状を維持し、行を絞り込み、ビューとコピーを使い分ける方法を説明します。

このページの内容

2 次元 NumPy 配列から 1 つの列を選択するには、array[:, column_index] を使用します。コロンはすべての行を選択し、整数はゼロ始まりの列を選択します。たとえば、data[:, 1] は 2 番目の列を 1 次元配列として返します。後続のコードで 2 次元の (rows, 1) 形式が必要な場合は、代わりに data[:, 1:2] を使用します。

1 つの列を選択して形状を制御する

NumPy では、2 次元配列を array[row_selection, column_selection] の形式でインデックス指定します。カンマを省くと処理が変わります。data[:][1] は、まず全体のスライスを作成してから行 1 を選択するため、列 1 は選択されません。

次の例では、一般的な列選択のケースを 1 つの再現可能なプログラムで示します。

import numpy as np

data = np.array([[10, 11, 12], [20, 21, 22], [30, 31, 32]])

second = data[:, 1]
second_2d = data[:, 1:2]
adjacent = data[:, :2]
reordered = data[:, [2, 0]]
taken = np.take(data, [0, 2], axis=1)
filtered = data[data[:, 0] >= 20, 2]

print("second:", second, second.shape)
print("second_2d:\n", second_2d, second_2d.shape)
print("adjacent:\n", adjacent)
print("reordered:\n", reordered)
print("taken:\n", taken)
print("filtered:", filtered)

view = data[:, 1]
copy = data[:, 1].copy()
view[0] = 99
print("data after view edit:\n", data)
print("copy:", copy)

出力:

second: [11 21 31] (3,)
second_2d:
 [[11]
 [21]
 [31]] (3, 1)
adjacent:
 [[10 11]
 [20 21]
 [30 31]]
reordered:
 [[12 10]
 [22 20]
 [32 30]]
taken:
 [[10 12]
 [20 22]
 [30 32]]
filtered: [22 32]
data after view edit:
 [[10 99 12]
 [20 21 22]
 [30 31 32]]
copy: [11 21 31]

整数の列インデックスはその軸を削除するため、second の形状は (3,) になります。要素を 1 つだけ含むスライスでは軸が維持され、second_2d の形状は (3, 1) になります。この違いは、API が平坦なベクトルではなく行列形式の入力を要求する場合に重要です。

複数の列を選択する

隣接する列には data[:, :2] のようなスライスを使用します。スライスは連続した範囲を表し、通常はビューを生成します。離れた列や任意の順序にはインデックスリスト data[:, [2, 0]] を指定します。これは高度なインデックス指定であり、ビューではなくコピーを生成します。

インデックスリストでは列の軸が常に維持されます。そのため、data[:, [1]] の形状は (3, 1) ですが、data[:, 1] の形状は (3,) です。リストでは列を繰り返したり位置を変えたりできるため、動的に指定されたインデックスで重複や順序が意外な結果になる場合は検証してください。列が単純な範囲ならスライスを、選択対象自体がシーケンスならインデックスリストを使用します。

np.take は軸を明示できる別の方法です。np.take(data, [0, 2], axis=1) は列 0 と列 2 を選択します。列は 2 番目の軸にあるため axis=1 が不可欠です。軸やインデックスを変数に保存している場合に特に便利です。

列を読み取る前に行をフィルタリングする

ブール条件は通常、列ではなく行を特定します。1 つの列から行マスクを作り、カンマの後に出力する列を指定します。この例では data[:, 0] >= 20 が最後の 2 行を保持し、data[data[:, 0] >= 20, 2] が列 2 から [22 32] を返します。マスクの長さは行数と一致している必要があります。

ビューとコピーのどちらが必要かを判断する

NumPy のインデックス指定の規則によると、基本的なスライスは可能な場合にビューを返し、高度なインデックス指定はコピーを返します。そのため、view = data[:, 1] を介して代入すると、出力の 99 が示すように data が変わることがあります。抽出した列を独立させる必要がある場合は .copy() を呼び出してください。ビューが元の配列を変更した後も、コピーした値は [11 21 31] のままです。

また、ビューは基になる配列のメモリを参照可能な状態に保ちます。大きな元配列の残りが不要になった後も保持するとメモリを浪費する場合は、小さな列をコピーしてください。

次元と列の範囲を確認する

これらの式は 2 次元配列を前提とします。1 次元配列には列軸がないため、array[:, 0] はインデックスエラーを発生させます。入力形状が不明な場合は array.ndim == 2 を確認してください。2 次元配列で有効な非負の列インデックスは 0 から array.shape[1] - 1 までで、範囲外のインデックスは IndexError を発生させます。範囲内なら負のインデックスも有効なので、array[:, -1] は最後の列を選択します。