3.2.3 配列のインデックスとスライス

- 1次元配列と多次元配列の基本インデックスとスライスを理解する
- ブールインデックスを使った条件抽出を学ぶ
- ファンシーインデックス(Fancy Indexing)を理解する
- ビュー(View)とコピー(Copy)の違いを理解する
1次元配列のインデックスとスライス
Section titled “1次元配列のインデックスとスライス”1次元配列のインデックスは、Python のリストと基本的に同じです:
import numpy as np
arr = np.array([10, 20, 30, 40, 50, 60, 70, 80])
# ===== 基本インデックス =====print(arr[0]) # 10 最初の要素print(arr[3]) # 40 4番目の要素print(arr[-1]) # 80 最後の要素print(arr[-2]) # 70 末尾から2番目の要素
# ===== スライス [start:stop:step] =====print(arr[2:5]) # [30 40 50] インデックス 2 から 4print(arr[:3]) # [10 20 30] 最初の3個print(arr[5:]) # [60 70 80] インデックス 5 から末尾までprint(arr[::2]) # [10 30 50 70] 1つおきに取り出すprint(arr[::-1]) # [80 70 60 50 40 30 20 10] 逆順にする2次元配列のインデックスとスライス
Section titled “2次元配列のインデックスとスライス”2次元配列は [行, 列] の形でアクセスします:
matrix = np.array([ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])単一要素へのアクセス
Section titled “単一要素へのアクセス”print(matrix[0, 0]) # 1 0行0列print(matrix[1, 2]) # 7 1行2列print(matrix[-1, -1]) # 16 最後の行・最後の列行全体 / 列全体へのアクセス
Section titled “行全体 / 列全体へのアクセス”print(matrix[0]) # [1 2 3 4] 0行目(行全体)print(matrix[0, :]) # [1 2 3 4] 同じ意味。より明示的な書き方
print(matrix[:, 0]) # [ 1 5 9 13] 0列目(列全体)print(matrix[:, -1]) # [ 4 8 12 16] 最後の列行・列のスライス
Section titled “行・列のスライス”# 最初の2行、最初の3列を取り出すsub = matrix[:2, :3]print(sub)# [[1 2 3]# [5 6 7]]
# 1〜2行目、2〜3列目を取り出すsub2 = matrix[1:3, 2:4]print(sub2)# [[ 7 8]# [11 12]]
# 1つおきに行を取り出す(0行目、2行目)sub3 = matrix[::2]print(sub3)# [[ 1 2 3 4]# [ 9 10 11 12]]2次元インデックスの図解
Section titled “2次元インデックスの図解”| 式 | 取り出すもの | 結果 |
|---|---|---|
matrix[1, 2] | 1行目、2列目 | 7 |
matrix[:2, :3] | 最初の2行、最初の3列 | [[1,2,3], [5,6,7]] |
matrix[:, 1] | すべての行、1列目 | [2, 6, 10, 14] |
ブールインデックス:条件抽出
Section titled “ブールインデックス:条件抽出”これは NumPy のとても強力な機能の1つです。条件式を使って、データを直接抽出できます。
基本の考え方
Section titled “基本の考え方”arr = np.array([15, 23, 8, 42, 31, 5, 19, 27])
# 1段階目:条件式からブール配列を作るmask = arr > 20print(mask) # [False True False True True False False True]
# 2段階目:ブール配列をインデックスとして使い、True に対応する要素を取り出すresult = arr[mask]print(result) # [23 42 31 27]
# 通常は1行でまとめて書けるprint(arr[arr > 20]) # [23 42 31 27]よく使う条件抽出
Section titled “よく使う条件抽出”scores = np.array([85, 92, 78, 65, 95, 43, 88, 72, 55, 90])
# 合格点(>= 60)print(scores[scores >= 60]) # [85 92 78 65 95 88 72 90]
# 優秀点(>= 90)print(scores[scores >= 90]) # [92 95 90]
# 不合格点(< 60)print(scores[scores < 60]) # [43 55]
# 60〜80 の点数(複数条件は & でつなぐ。各条件はかっこで囲む)print(scores[(scores >= 60) & (scores <= 80)]) # [78 65 72]
# 60未満または90より高い点数(複数条件は | でつなぐ)print(scores[(scores < 60) | (scores > 90)]) # [92 95 43 55]
# 反転(~)print(scores[~(scores >= 60)]) # [43 55] scores[scores < 60] と同じ2次元配列でのブールインデックス
Section titled “2次元配列でのブールインデックス”matrix = np.array([ [85, 92, 78], [65, 95, 43], [88, 72, 90]])
# 80より大きい点数をすべて取り出すprint(matrix[matrix > 80]) # [85 92 95 88 90]# 注意:結果は1次元配列になります!
# 不合格点を60に変更する(条件付き代入)matrix[matrix < 60] = 60print(matrix)# [[85 92 78]# [65 95 60] ← 43 が 60 に変わった# [88 72 90]]ファンシーインデックス(Fancy Indexing)
Section titled “ファンシーインデックス(Fancy Indexing)”ファンシーインデックスでは、整数配列をインデックスとして使い、指定した位置の要素をまとめて取り出せます。
1次元のファンシーインデックス
Section titled “1次元のファンシーインデックス”arr = np.array([10, 20, 30, 40, 50, 60, 70])
# インデックス 1, 3, 5 の要素を取り出すprint(arr[[1, 3, 5]]) # [20 40 60]
# 同じ要素を繰り返し取り出せるprint(arr[[0, 0, 2, 2]]) # [10 10 30 30]
# 好きな順番で取り出せるprint(arr[[6, 4, 2, 0]]) # [70 50 30 10]2次元のファンシーインデックス
Section titled “2次元のファンシーインデックス”matrix = np.array([ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# 0行目と2行目を取り出すprint(matrix[[0, 2]])# [[ 1 2 3 4]# [ 9 10 11 12]]
# 特定の位置:(0,1), (1,2), (2,3) の3要素を取り出すrows = [0, 1, 2]cols = [1, 2, 3]print(matrix[rows, cols]) # [ 2 7 12]ビュー(View)vs コピー(Copy)
Section titled “ビュー(View)vs コピー(Copy)”
ここは初心者がつまずきやすいポイントです。NumPy のスライスはコピーではなくビューを返します。
ビュー:変更すると元の配列にも影響する
Section titled “ビュー:変更すると元の配列にも影響する”arr = np.array([1, 2, 3, 4, 5])
# スライスはビューsub = arr[1:4]print(sub) # [2 3 4]
# sub を変更すると arr も変わる!sub[0] = 99print(sub) # [99 3 4]print(arr) # [ 1 99 3 4 5] ← 元の配列も変わった!コピー:互いに影響しない
Section titled “コピー:互いに影響しない”arr = np.array([1, 2, 3, 4, 5])
# copy() で独立したコピーを作るsub = arr[1:4].copy()print(sub) # [2 3 4]
# sub を変更しても arr は変わらないsub[0] = 99print(sub) # [99 3 4]print(arr) # [1 2 3 4 5] ← 元の配列は変わらないいつビュー? いつコピー?
Section titled “いつビュー? いつコピー?”| 操作 | 戻り値の種類 | 例 |
|---|---|---|
| スライス | ビュー | arr[2:5] |
| ブールインデックス | コピー | arr[arr > 3] |
| ファンシーインデックス | コピー | arr[[1, 3, 5]] |
.copy() | コピー | arr[2:5].copy() |
.reshape() | ビュー(通常) | arr.reshape(2, 3) |
実践例:インデックスでデータを分析する
Section titled “実践例:インデックスでデータを分析する”Titanic の場面に戻って、NumPy のインデックスを使ってデータを分析してみましょう。
import numpy as np
# 10人の乗客データを模したものages = np.array([22, 38, 26, 35, 35, np.nan, 54, 2, 27, 14])fares = np.array([7.25, 71.28, 7.92, 53.10, 8.05, 8.46, 51.86, 21.08, 11.13, 30.07])survived = np.array([0, 1, 1, 1, 0, 0, 0, 0, 1, 1])
# 生存者の平均運賃を求めるsurvivor_fares = fares[survived == 1]print(f"生存者の平均運賃: ${np.mean(survivor_fares):.2f}")
# 30歳より上の乗客の運賃を取り出す(NaN を除外する必要がある)valid_mask = ~np.isnan(ages) # NaN を除外age_mask = ages > 30combined_mask = valid_mask & age_maskprint(f"30歳以上の乗客の運賃: {fares[combined_mask]}")
# 運賃が高い上位3人の乗客のインデックスを取り出すtop3_indices = np.argsort(fares)[-3:][::-1] # 並べ替えた後、最後の3つを取り、逆順にするprint(f"運賃 Top 3 のインデックス: {top3_indices}")print(f"対応する運賃: {fares[top3_indices]}")このページを終えたら、この evidence card を残します。
- 配列状態
- 操作前の shape、dtype、axis、サンプル値
- 操作
- indexing、slicing、broadcasting、reshape、線形代数、またはランダム/stat関数
- 出力
- 結果の配列形状、値、または統計量
- 失敗確認
- 軸の混同、view/copy の落とし穴、ブロードキャスト不一致、または誤った形状
- 期待される成果
- 配列操作を確認できる出力形状と値
| インデックス方法 | 構文 | 戻り値の種類 | 適した場面 |
|---|---|---|---|
| 基本インデックス | arr[i], arr[i, j] | 要素値 | 単一要素を取得する |
| スライス | arr[start:stop:step] | ビュー | 連続した範囲を取得する |
| ブールインデックス | arr[arr > 5] | コピー | 条件で抽出する |
| ファンシーインデックス | arr[[1, 3, 5]] | コピー | 離れた位置の要素を取る |
手を動かしてみよう
Section titled “手を動かしてみよう”練習1:基本スライス
Section titled “練習1:基本スライス”arr = np.arange(1, 21) # [1, 2, 3, ..., 20]
# 1. 最初の5個の要素を取り出す# 2. すべての奇数位置の要素を取り出す(インデックス 1, 3, 5, ...)# 3. 最後の3個の要素を取り出す# 4. 配列を逆順にする練習2:2次元スライス
Section titled “練習2:2次元スライス”matrix = np.arange(1, 26).reshape(5, 5)print(matrix)# [[ 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]]
# 1. 真ん中の 3×3 の部分行列を取り出す# 2. 2列目のすべての要素を取り出す# 3. 対角線の要素 [1, 7, 13, 19, 25] を取り出す(ヒント:ファンシーインデックスを使う)練習3:ブールインデックスの実践
Section titled “練習3:ブールインデックスの実践”# あるクラス20人の数学の点数math_scores = np.array([ 78, 92, 65, 88, 45, 95, 72, 81, 56, 90, 83, 67, 94, 73, 85, 60, 98, 77, 69, 87])
# 1. すべての不合格点(< 60)を取り出す# 2. 80〜90 の点数(両端含む)を取り出す# 3. 合格した学生の平均点を計算する# 4. すべての不合格点を60に変更する# 5. 変更後の平均点を計算する参考実装と解説
- 代表的なスライスは、先頭 5 個が
arr[:5]、1 始まりで偶数番目の位置がarr[1::2]、末尾 3 個がarr[-3:]、逆順がarr[::-1]です。 - 5x5 行列では、
matrix[1:4, 1:4]が中央の 3x3 ブロック、matrix[:, 1]が 2 列目、matrix[np.arange(5), np.arange(5)]が主対角線を選びます。 - スコアのフィルタリングでは元データを残し、コピーした配列で不合格点を
60に置き換えます。これで生データという証拠を消さずに済みます。