Pythonにおける2次元配列は、データの表形式での管理や数学的な行列演算を行う際に非常に重要な役割を果たします。

標準のリスト機能を使う方法から、高度なライブラリであるNumPyを活用する方法まで、その扱いは多岐にわたります。

この記事では、実戦で使える効率的な2次元配列の作成方法や操作、注意点について詳しく解説します。

Pythonで2次元配列を扱う基本概念

Pythonには「2次元配列」という専用のデータ型は標準では存在しません。

一般的には、「リストの中にリストを入れる」ことで、2次元配列のような構造を表現します。

これを「ネストされたリスト」や「リストのリスト」と呼びます。

例えば、3行3列のデータを管理したい場合、外側のリストが「行」を、内側のリストが「列」の要素を保持する形になります。

プログラミングにおいて、複数のデータを格子状に管理するシーンは非常に多く、この手法をマスターすることは不可欠です。

2次元配列の作成方法と初期化の注意点

もっともシンプルに2次元配列を作成するには、値を直接記述する方法があります。

Python
# 直接値を指定して作成する
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
print(matrix)
実行結果
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

内包表記を使った効率的な初期化

特定のサイズで、すべての要素が0の2次元配列を作りたい場合は、「リスト内包表記」を使うのが最も推奨される方法です。

Python
# 3行4列の0埋め配列を作成
rows = 3
cols = 4
matrix = [[0 for _ in range(cols)] for _ in range(rows)]
print(matrix)
実行結果
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

避けるべき初期化の書き方

「[[0] * cols] * rows」という書き方は絶対に行わないでください。

この書き方では、内側のリストがすべて同じメモリを参照してしまいます。

その結果、1カ所の要素を書き換えると、すべての行の同じ列が同時に書き換わってしまうというバグを引き起こします。

Python
# 悪い例:浅いコピーによる不具合
bad_matrix = [[0] * 3] * 3
bad_matrix[0][0] = 9
print(bad_matrix)
実行結果
[[9, 0, 0], [9, 0, 0], [9, 0, 0]]

2次元配列の要素へのアクセスと更新

2次元配列の特定の要素にアクセスするには、リスト名[行インデックス][列インデックス]の形式を使用します。

Pythonのインデックスは 0 から始まるため、1行目の2列目にアクセスしたい場合は [0][1] と記述します。

要素の取得と書き換え

Python
matrix = [
    [10, 20, 30],
    [40, 50, 60]
]

# 要素の取得
val = matrix[1][2]
print(f"要素の取得: {val}")

# 要素の更新
matrix[1][2] = 999
print(f"更新後の配列: {matrix}")
実行結果
要素の取得: 60
更新後の配列: [[10, 20, 30], [40, 50, 999]]

ループ処理による全要素の走査

2次元配列のすべての要素を順番に処理するには、for文を入れ子(二重ループ)にします。

Python
matrix = [[1, 2], [3, 4], [5, 6]]

for row in matrix:
    for item in row:
        print(item, end=" ")
    print() # 改行用
実行結果
1 2 
3 4 
5 6

2次元配列に対する便利な操作テクニック

実務では、2次元配列の行を追加したり、列を抽出したりする操作が頻繁に発生します。

行の追加と削除

行を追加するには、通常のリストと同様に append() メソッドを使用します。

Python
matrix = [[1, 2], [3, 4]]
# 行の追加
matrix.append([5, 6])
print(matrix)
実行結果
[[1, 2], [3, 4], [5, 6]]

行を削除するには pop()del を使用します。

特定の列を抽出する

標準のリストでは、matrix[:][0] のような記述で列を抽出することはできません。

列を取り出すには、リスト内包表記を使用するのがスマートです。

Python
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
# 2列目(インデックス1)を抽出
column_1 = [row[1] for row in matrix]
print(column_1)
実行結果
[2, 5, 8]

行と列の入れ替え(転置)

行と列を入れ替える操作(転置)は、zip() 関数とアスタリスク引数(アンパック)を使うことで簡単に実現できます。

Python
matrix = [
    [1, 2, 3],
    [4, 5, 6]
]
transpose = [list(x) for x in zip(*matrix)]
print(transpose)
実行結果
[[1, 4], [2, 5], [3, 6]]

NumPyを使用した高度で高速な2次元配列操作

大量のデータを扱う場合や数学的な計算を行う場合は、標準のリストではなく NumPy ライブラリを使用するのが一般的です。

NumPyの ndarray オブジェクトは、メモリ効率が高く、処理速度が非常に高速です。

NumPy配列の作成

Python
import numpy as np

# リストからNumPy配列を作成
np_matrix = np.array([
    [1, 2, 3],
    [4, 5, 6]
])
print(np_matrix)
実行結果
[[1 2 3]
 [4 5 6]]

NumPy独自の便利なスライス操作

NumPyでは、カンマ区切りでインデックスを指定することで、直感的に特定範囲の要素(部分行列)を抽出できます。

Python
# すべての行の0列目を取得
print(np_matrix[:, 0])

# 特定の範囲を抽出
print(np_matrix[0:2, 1:3])
実行結果
[1 4]
[[2 3]
 [5 6]]

配列同士の計算

NumPyの最大の利点は、ループを書かずに配列全体の計算ができる「ベクトル化演算」です。

Python
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])

# 加算
print(a + b)

# 要素ごとの掛け算
print(a * b)
実行結果
[[ 6  8]
 [10 12]]
[[ 5 12]
 [21 32]]

2次元配列の活用シーン

2次元配列は、システム開発やデータ分析のあらゆる場面で活用されています。

活用シーン具体的な内容
CSV/Excelデータの処理行と列で構成されるスプレッドシート形式のデータをプログラム内で保持。
画像処理ピクセルの並びを(高さ, 幅)の2次元配列(またはRGBを含めた3次元)として扱う。
ゲーム開発迷路やチェス、タイルベースのマップ情報を座標形式で管理。
機械学習特徴量行列(行がサンプル、列が項目)としてアルゴリズムの入力に使用。

まとめ

Pythonで2次元配列を扱う方法は、用途によって使い分けるのがベストです。

小規模なデータや単純な構造であれば、リスト内包表記を活用した標準リストが便利です。

一方で、データサイズが大きい場合や行列演算が必要な場合は、NumPyの導入を検討してください。

特に初期化時の「浅いコピー」によるバグは初心者が陥りやすいポイントであるため、常に注意を払いましょう。

これらのテクニックを組み合わせることで、複雑なデータ構造をより効率的に、そして安全に制御できるようになります。