インデックス作成とスライシング
1. 学習内容
- ❶ 1次元配列のインデックス指定とスライシング:1次元配列からの添字によるアクセスと範囲の抽出
- ❷ 2次元インデックス:行、列、および部分行列の抽出
- ❸ 3Dインデックス付けの直感:高次元配列をレイヤーごとに考える
- ❹ ステップスライシング:正のステップ、負のステップ、および負のインデックス
- ❺ スライスはビューである:ビューとコピーの本質的な違いを理解する
2. ストーリー
チャーリーは、10,000行のセンサーデータ行列を分析しています。彼はdata[0:3]を使用して、外れ値の除去のために最初の3行を取り出し、欠損値を-1に設定しています:
subset = data[0:3]
subset[subset == -999] = -1
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
掃除を終えたsubsetは、見違えるほどきれいになった。しかし、元のdataを確認してみると、最初の3行も変更されていた!
「スライスはコピーではなく、ビューを返すのよ!」とアリスは説明する。
彼女はチャーリーに、オリジナルに影響を与えない安全な操作を行うためのsubset = data[0:3].copy()の使い方を教える。チャーリーは痛い目に遭って学ぶことになる。NumPyのスライスはデフォルトでメモリを共有する――これがその効率性の源であると同時に、落とし穴の根源でもある。
3. 主要な概念
(1) 基本的なインデックス作成
1次元配列のインデックス指定はPythonのリストと同様に機能します。0から始まり、負のインデックスは-1から数えられます。
import numpy as np
a = np.array([10, 20, 30, 40, 50])
a[0] # 10
a[-1] # 50
a[2] # 30
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(2) スライス構文
スライス形式:start:stop:step。3つの部分すべてがオプションです:
| 略語 | 対応する語 | 意味 |
|---|---|---|
a[:] |
a[0:len(a):1] |
すべての要素 |
a[2:] |
a[2:len(a):1] |
インデックス 2 から末尾まで |
a[:3] |
a[0:3:1] |
最初の3つの要素 |
a[::2] |
a[0:len(a):2] |
1つおきに |
a[::-1] |
a[len(a)-1::-1] |
配列を逆順にする |
a = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
a[2:7] # [2 3 4 5 6]
a[::3] # [0 3 6 9]
a[::-1] # [9 8 7 6 5 4 3 2 1 0]
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(3) 2次元インデックス付け
import numpy as np
a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# Row and column
print(a[1]) # [4 5 6 7] — row 1
print(a[1, 2]) # 6 — row 1, col 2
# Sub-matrix
print(a[:2, 1:3])
# [[1 2]
# [5 6]]
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(4) 3Dインデクシングの直感
3次元配列を「2次元行列の層」と捉えてみてください:
import numpy as np
a = np.arange(24).reshape(2, 3, 4)
print(a.shape) # (2, 3, 4)
# Layer 0: first 3x4 matrix
print(a[0])
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# Layer 1: second 3x4 matrix
print(a[1])
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]
# Single element: a[layer, row, col]
print(a[1, 2, 3]) # 23
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(5) ビューとコピー
スライスは常にビューを返します。 スライスを変更すると、元の配列も変更されます。
import numpy as np
a = np.arange(12).reshape(3, 4)
view = a[0:2, 1:3]
view[0, 0] = 999
print(a)
# [[ 0 999 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# The original changed!
# Use .copy() for a safe copy
copy = a[0:2, 1:3].copy()
copy[0, 0] = 0
print(a[0, 1]) # 999 — original unchanged by copy
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(1) ▶ サンプル
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
: ステップを用いた1次元スライシング (難易度 ⭐)
import numpy as np
a = np.arange(10)
print("Original:", a)
# [0 1 2 3 4 5 6 7 8 9]
print("a[2:8:2]:", a[2:8:2]) # [2 4 6]
print("a[::-1]:", a[::-1]) # [9 8 7 6 5 4 3 2 1 0]
print("a[5:1:-1]:", a[5:1:-1]) # [5 4 3 2]
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(2) ▶ サンプル
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
: 2次元部分行列の抽出 (難易度 ⭐⭐)
import numpy as np
a = np.arange(20).reshape(4, 5)
print("Original:\n", a)
# Extract rows 1-2, cols 2-4
sub = a[1:3, 2:5]
print("a[1:3, 2:5]:\n", sub)
# [[ 7 8 9]
# [12 13 14]]
# Every other row, every other column
print("a[::2, ::2]:\n", a[::2, ::2])
# [[ 0 2 4]
# [10 12 14]]
> Output: Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
4. 比較表
(1) スライスのバリエーション
| スライス | 意味 | [0,1,2,3,4,5] の検索結果 |
|---|---|---|
[:] |
すべて | [0 1 2 3 4 5] |
[2:] |
インデックス 2 より | [2 3 4 5] |
[:3] |
最初の3件 | [0 1 2] |
[1:4] |
インデックス 1 ~ 3 | [1 2 3] |
[::2] |
隔日 | [0 2 4] |
[::-1] |
反転 | [5 4 3 2 1 0] |
(2) 表示とコピー
| 機能 | スライス (表示) | ファンシーインデックス (コピー) |
|---|---|---|
| 構文 | a[1:3] |
a[[1, 2, 3]] |
| 戻る | 表示 | コピー |
| メモリ | 共有 | 新規割り当て |
| 変更は元データに影響しますか | はい | いいえ |
| 速度 | O(1) | O(n) |
(1) ▶ サンプル:多次元スライシングにおける省略記号の使用(難易度 ⭐⭐)
import numpy as np
arr = np.arange(24).reshape(2, 3, 4)
print("Shape:", arr.shape)
# Ellipsis (...) means "all remaining dimensions"
print("arr[0, ...]:\n", arr[0, ...])
print("arr[..., 0]:\n", arr[..., 0])
# Select last column for all layers and rows
print("arr[..., -1]:\n", arr[..., -1])
出力:
TEXT形状:(2, 3, 4) arr[0, ...]: [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] arr[..., 0]: [[ 0 4 8] [12 16 20]] arr[..., -1]: [[ 3 7 11] [15 19 23]]
❓ よくある質問
.copy() を明示的に使用してください:a[1:3].copy()。あるいは、常にコピーを返す a[[0, 1, 2]] のような「ファンシーインデックス」を使用してください。...(省略記号)は「残りのすべての次元」を表します。 a[..., 0] は、「他のすべての次元について、最後の次元からインデックス 0 を選択する」という意味です。高次元配列で役立ちます。a[1:3] = [99, 100]は要素1と2を置き換えます。これは非常に便利な機能で、配列の一部をその場で変更することができます。📖 まとめ
- 基本インデックス:
a[i]は要素 i にアクセスします。負のインデックスは末尾から数えます。 - スライス構文:
start:stop:step— すべての部分は省略可能。負のステップは進行方向を逆転させる - 2Dインデックス指定:
a[row, col]— スライスと整数を自由に組み合わせる - 3D+インデックス作成:レイヤー単位で考える;3Dについては
a[layer, row, col] - スライスするとビューが返される — それらを変更すると、元の配列が変更される
.copy()を使用して、安全で独立したコピーを入手してください
📝 練習問題
-
初心者向け(難易度 ⭐):
a = np.arange(15)を作成してください。そこから、(a) 最初の 5 つの要素、(b) 最後の 3 つの要素、(c) 偶数番目の要素、(d) 配列を逆順にしたものを抽出してください。 -
中級(難易度 ⭐⭐):0~24の値で構成される5×5の配列を作成してください。 そこから、(a) 中央の3×3の部分行列、(b) 最初と最後の行、(c) すべての偶数行と奇数列を抽出してください。部分行列を変更すると元の行列も変化することを確認してください。
-
上級(難易度 ⭐⭐⭐):3×4×5の配列を作成してください。
...を使用して、すべてのレイヤーと行の最後の列を選択してください。 次に、a[0, ...]を使用して最初のレイヤーを選択してください。それぞれのケースにおいて、...がどのような動作をするかを説明してください。