HOWTO · NumPy

如何從 NumPy 陣列中取得欄

從二維 NumPy 陣列中選取一欄或多欄、保留所需形狀、篩選列,並依需求選擇檢視或複本。

本頁內容

對於二維 NumPy 陣列,可使用 array[:, column_index] 選取一欄。冒號會選取所有列,整數則選取從零開始編號的欄。例如,data[:, 1] 會將第二欄作為一維陣列傳回。若後續程式碼要求二維的 (rows, 1) 結果,請改用 data[:, 1:2]。

選取一欄並控制其形狀

NumPy 使用 array[row_selection, column_selection] 的形式為二維陣列建立索引。省略逗號會改變操作:data[:][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,) 的原因。只有一個元素的切片會保留該軸,因此 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;由於欄位於第二個軸,axis=1 不可省略。當軸或索引儲存在變數中時,此方法特別實用。

讀取欄之前篩選列

布林條件通常識別列,而不是欄。先根據某一欄建立列遮罩,再於逗號後指定所需的輸出欄。在範例中,data[:, 0] >= 20 會保留最後兩列,而 data[data[:, 0] >= 20, 2] 會傳回欄 2 中的 [22 32]。遮罩長度必須與列數相同。

判斷需要檢視還是複本

根據 NumPy 的索引規則,基本切片會在可能時傳回檢視,而進階索引則傳回複本。因此,透過 view = data[:, 1] 指派值可能會變更 data,輸出中的 99 就說明了這一點。若擷取的欄必須獨立存在,請呼叫 .copy()。檢視變更來源陣列後,複製的值仍為 [11 21 31]。

這些檢視也會使其基礎陣列的記憶體保持可存取狀態。如果僅保留一個小欄,卻導致不再需要的大型來源陣列持續占用記憶體,請複製該欄。

檢查維度與欄邊界

這些運算式假設陣列是二維的。一維陣列沒有欄軸,因此 array[:, 0] 會引發索引錯誤。當輸入形狀不確定時,請檢查 array.ndim == 2。對於二維陣列,有效的非負欄索引範圍是 0 到 array.shape[1] - 1;超出此範圍的索引會引發 IndexError。負索引在邊界內也有效,因此 array[:, -1] 會選取最後一欄。