NumPy配列のスライス徹底解説:部分配列の選択と効率的な代入


 

データサイエンスや機械学習において、NumPy配列(ndarray) の操作は非常に重要です。特に、配列の特定の部分を取り出したり、まとめて値を変更したりする際には、スライスが不可欠なテクニックとなります。この記事では、NumPy配列におけるスライスを用いた部分配列の選択方法と、効率的な値の代入について詳しく解説します。


 

NumPyスライスとは?

 

NumPyのスライスは、Pythonのリストのスライスに似ていますが、多次元配列に適用できる点が大きく異なります。これにより、配列から特定の行、列、または任意の矩形領域を柔軟に抽出できます。スライスの基本形式は [開始インデックス:終了インデックス:ステップ] で、終了インデックスは範囲に含まれません。

 

基本的なスライスの使い方

 

まずは一次元配列でスライスの基本を確認しましょう。

Python
 
import numpy as np

arr = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])

# インデックス2から5まで(5は含まない)
sub_arr1 = arr[2:5]
print(f"2から5まで: {sub_arr1}") # 出力: [20 30 40]

# 最初からインデックス4まで
sub_arr2 = arr[:5]
print(f"最初から5まで: {sub_arr2}") # 出力: [0 10 20 30 40]

# インデックス5から最後まで
sub_arr3 = arr[5:]
print(f"5から最後まで: {sub_arr3}") # 出力: [50 60 70 80 90]

# 2つ飛ばしで取得
sub_arr4 = arr[::2]
print(f"2つ飛ばし: {sub_arr4}") # 出力: [ 0 20 40 60 80]

 

多次元NumPy配列のスライス

 

NumPy配列の真価は、多次元データに対するスライスで発揮されます。各次元に対して個別にスライスを指定します。

 

特定の行・列の選択

 

: (コロン) を単独で使うと、「その次元のすべて」を意味します。

Python
 
import numpy as np

arr_2d = np.array([[10, 20, 30],
                   [40, 50, 60],
                   [70, 80, 90]])

# 1行目全体を取得 (インデックス0から始まる)
row_1 = arr_2d[0, :]
print(f"1行目: {row_1}") # 出力: [10 20 30]

# 2列目全体を取得 (インデックス0から始まる)
col_2 = arr_2d[:, 1]
print(f"2列目: {col_2}") # 出力: [20 50 80]

 

部分配列(サブアレイ)の選択

 

複数の次元にスライスを適用することで、配列の任意の矩形部分を抽出できます。

Python
 
import numpy as np

arr_2d = np.array([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])

# 1行目から2行目、かつ2列目から3列目の部分配列
sub_arr = arr_2d[0:2, 1:3]
print(f"部分配列:\n{sub_arr}")
# 出力:
# [[2 3]
#  [6 7]]

# 最後の行と列を取得
last_row_col = arr_2d[-1, -1]
print(f"最後の要素: {last_row_col}") # 出力: 12

 

スライスによる部分配列への代入

 

NumPyのスライスの強力な機能の一つは、抽出した部分配列に対して直接値を代入できる点です。これにより、配列の一部を一括で変更できます。

 

単一の値を代入

 

Python
 
import numpy as np

arr = np.array([[1, 2, 3],
                [4, 5, 6],
                [7, 8, 9]])

# 1行目全体を0に代入
arr[0, :] = 0
print(f"1行目を0に代入後:\n{arr}")
# 出力:
# [[0 0 0]
#  [4 5 6]
#  [7 8 9]]

 

別の配列を代入

 

代入する配列の形状が、スライスで選択した部分配列の形状と一致している必要があります。

Python
 
import numpy as np

arr = np.array([[1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]])

# 2行目と3行目の2,3列目に新しい値を代入
arr[1:3, 1:3] = np.array([[99, 88],
                          [77, 66]])
print(f"部分代入後の配列:\n{arr}")
# 出力:
# [[ 1,  2,  3,  4],
#  [ 5, 99, 88,  8],
#  [ 9, 77, 66, 12]]

 

スライスの「ビュー」と「コピー」に注意

 

NumPyのスライスは、通常、元の配列のビュー(view) を返します。これは、スライスされた部分配列を変更すると、元の配列も変更されることを意味します。パフォーマンスの観点からは効率的ですが、意図しないデータ変更につながる可能性があるので注意が必要です。

 

ビューの挙動

 

Python
 
import numpy as np

arr = np.array([1, 2, 3, 4, 5])
view_arr = arr[1:4] # ビューを作成

view_arr[0] = 99 # ビューの要素を変更
print(f"元の配列: {arr}") # 出力: 元の配列: [ 1 99  3  4  5]

 

明示的にコピーを作成する

 

元の配列に影響を与えずにスライスされた部分を操作したい場合は、copy() メソッドを使って明示的にコピーを作成します。

Python
 
import numpy as np

arr = np.array([1, 2, 3, 4, 5])
copied_arr = arr[1:4].copy() # コピーを作成

copied_arr[0] = 99 # コピーの要素を変更
print(f"元の配列: {arr}")     # 出力: 元の配列: [1 2 3 4 5] (変更なし)
print(f"コピー配列: {copied_arr}") # 出力: コピー配列: [99  3  4]

 

まとめ

 

NumPy配列のスライスは、データ操作の基本でありながら非常に強力なツールです。単一の要素から複雑な部分配列まで柔軟に選択し、効率的に値を代入することができます。また、ビューとコピーの概念を理解することは、予期せぬバグを防ぎ、より堅牢なコードを書く上で不可欠です。これらのテクニックを習得して、あなたのデータ分析スキルをさらに向上させましょう!