NumPy Reshape:Pythonで配列の形状を変更する方法
Updated on
10,000個のピクセル値のフラットなリストがあり、ニューラルネットワークは100x100の画像行列を期待しています。あるいは、特徴量配列が1次元であるのに列ベクトルが必要なため、scikit-learnがエラーを投げているかもしれません。これらはエッジケースではありません -- Pythonで数値データを扱う人にとって日常的な障害です。これらを解決する関数がnumpy.reshape()であり、正しく理解すればデバッグの時間を何時間も節約できます。
numpy reshapeは何をするのか?
numpy.reshape()は、データを変更せずに配列の形状を変更します。同じ要素を取り、新しい次元のセットに再配置します。12要素の1D配列は、3x4行列、2x6行列、4x3行列、さらには2x2x3の3次元配列にもなります。唯一のルールは、要素の総数が同じでなければならないことです。
import numpy as np
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
print(a.shape)
# (12,)
b = a.reshape(3, 4)
print(b)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
print(b.shape)
# (3, 4)元の配列aは元の形状のまま存在し続けます。reshape後の配列bは同じデータの新しいビューです(ビューとコピーについては後述)。
基本的な構文とパラメータ
NumPyで配列をreshapeする方法は2つあります:
# 方法1:関数として
np.reshape(array, newshape, order='C')
# 方法2:配列のメソッドとして
array.reshape(newshape, order='C')| パラメータ | 型 | 説明 |
|---|---|---|
array | ndarray | reshapeする配列(np.reshape()関数形式でのみ使用) |
newshape | intまたはintのタプル | 目標の形状。1つの次元を-1にでき、自動的に計算されます。 |
order | 'C'、'F'、または'A' | 要素の読み書き順序。'C' = 行優先(デフォルト)、'F' = 列優先、'A' = 配列がFortran連続ならFortran順、そうでなければC順。 |
どちらの形式も同じ結果を生成します。メソッド形式(array.reshape())の方がコード中で自然に読めるため、より一般的です。
1Dから2D配列へのreshape
これは最も頻繁なreshape操作です。フラットな配列から始めて行列が必要な場合です。
import numpy as np
# 8要素の1D配列
data = np.array([10, 20, 30, 40, 50, 60, 70, 80])
# 2行4列にreshape
matrix_2x4 = data.reshape(2, 4)
print(matrix_2x4)
# [[10 20 30 40]
# [50 60 70 80]]
# 4行2列にreshape
matrix_4x2 = data.reshape(4, 2)
print(matrix_4x2)
# [[10 20]
# [30 40]
# [50 60]
# [70 80]]
# 列ベクトルにreshape(8行1列)
column_vector = data.reshape(8, 1)
print(column_vector)
# [[10]
# [20]
# [30]
# [40]
# [50]
# [60]
# [70]
# [80]]
print(column_vector.shape)
# (8, 1)列ベクトルへのreshape(n, 1)は特に重要です。多くのscikit-learn関数は、単一の特徴量であっても2D入力を必要とします。1D配列を渡すと、Expected 2D array, got 1D array insteadというエラーが発生します。修正方法は.reshape(-1, 1)です。
2Dから3Dへのreshape(機械学習とディープラーニング向け)
TensorFlowやPyTorchなどのディープラーニングフレームワークは、しばしば3Dまたは4Dの入力テンソルを必要とします。例えば、グレースケール画像のバッチは(batch_size, height, width)の形状が必要で、カラー画像のバッチは(batch_size, height, width, channels)が必要です。
import numpy as np
# 2D配列の行として格納された4枚の3x3グレースケール画像をシミュレート
images_2d = np.arange(36).reshape(4, 9)
print(images_2d.shape)
# (4, 9)
# (バッチ、高さ、幅)にreshape
images_3d = images_2d.reshape(4, 3, 3)
print(images_3d.shape)
# (4, 3, 3)
print(images_3d[0])
# [[0 1 2]
# [3 4 5]
# [6 7 8]]3チャンネル(RGB)のカラー画像の場合:
import numpy as np
# 2枚のカラー画像、各4x4で3チャンネル、フラットに格納
flat_data = np.arange(96) # 2 * 4 * 4 * 3 = 96
images = flat_data.reshape(2, 4, 4, 3)
print(images.shape)
# (2, 4, 4, 3)-1トリック:1つの次元を自動計算
1つの次元を-1に設定すると、NumPyは要素の総数と指定した他の次元に基づいて自動的に計算します。これはreshapeの最も便利な機能の1つです。
import numpy as np
arr = np.arange(12)
# 「3行にして、列は計算して」
print(arr.reshape(3, -1))
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 形状: (3, 4) -- NumPyが4列を計算
# 「2列にして、行は計算して」
print(arr.reshape(-1, 2))
# [[ 0 1]
# [ 2 3]
# [ 4 5]
# [ 6 7]
# [ 8 9]
# [10 11]]
# 形状: (6, 2) -- NumPyが6行を計算
# 1Dにフラット化
print(arr.reshape(-1))
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
# 形状: (12,)
# 列ベクトル
print(arr.reshape(-1, 1).shape)
# (12, 1)-1は1つの次元にしか使用できません。2つ以上の次元に使用すると、計算が曖昧になるためエラーが発生します。
import numpy as np
arr = np.arange(12)
# これは失敗します:
# arr.reshape(-1, -1)
# ValueError: can only specify one unknown dimensionreshape()とresize()の違い:主な相違点
どちらの関数も配列の形状を変更しますが、動作は大きく異なります。
| 特徴 | reshape() | resize() |
|---|---|---|
| 戻り値 | 新しい配列(ビューまたはコピー) | 配列をインプレースで変更(メソッド)または新しい配列を返す(関数) |
| サイズの一致が必要 | はい -- 要素の総数が同じでなければならない | いいえ -- ゼロで埋めるか切り詰める |
| 元の配列 | 変更なし | 変更される(ndarray.resize()使用時) |
| 安全性 | サイズ不一致でエラーを発生 | 黙って埋めるか切り詰める |
| 一般的な用途 | 次元の再配置 | 配列サイズの変更 |
import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
# reshape:同じ要素総数を維持する必要がある
reshaped = arr.reshape(2, 3)
print(reshaped)
# [[1 2 3]
# [4 5 6]]
# np.resize(関数形式):新しいサイズが大きい場合、繰り返しで埋める
resized = np.resize(arr, (3, 3))
print(resized)
# [[1 2 3]
# [4 5 6]
# [1 2 3]] <-- 最初から繰り返し
# np.resize:新しいサイズが小さい場合、切り詰める
resized_small = np.resize(arr, (2, 2))
print(resized_small)
# [[1 2]
# [3 4]]データを変更せずに次元を再配置したい場合はreshape()を使用してください。要素数を本当に変更する必要がある場合にのみresize()を使用してください。
orderパラメータ:C vs F vs A
orderパラメータは、元の配列から要素がどのように読み取られ、新しい形状に配置されるかを制御します。異なるプログラミング言語やストレージフォーマットのデータを扱う際に重要です。
import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
# C順序(行優先):行ごとに埋める -- これがデフォルト
c_order = arr.reshape(2, 3, order='C')
print("C順序:")
print(c_order)
# [[1 2 3]
# [4 5 6]]
# F順序(列優先):列ごとに埋める
f_order = arr.reshape(2, 3, order='F')
print("F順序:")
print(f_order)
# [[1 3 5]
# [2 4 6]]| Order | 名前 | 埋め方 | ユースケース |
|---|---|---|---|
'C' | Cスタイル / 行優先 | 行ごと(最後のインデックスが最も速く変化) | Python/C/C++のデフォルトメモリレイアウト |
'F' | Fortranスタイル / 列優先 | 列ごと(最初のインデックスが最も速く変化) | MATLAB、Fortran、Rのデータ |
'A' | 自動 | 配列がFortran連続ならF、そうでなければC | 既存のメモリレイアウトを維持 |
ほとんどの場合、デフォルトの'C'順序を使用します。MATLABやFortranからエクスポートされたデータを読み込む際に'F'順序が必要です。これらの環境では行列が列ごとに格納されています。
ビューとコピー:reshapeがビューを返す場合
重要な詳細:reshape()は可能な限り元の配列のビューを返します。ビューは同じ基礎メモリを共有します。ビューを変更すると元の配列も変更され、その逆も同様です。
import numpy as np
original = np.arange(6)
reshaped = original.reshape(2, 3)
# reshape後のビューを変更
reshaped[0, 0] = 999
print(original)
# [999 1 2 3 4 5] <-- 元の配列も変更された!NumPyがビューを作成できない場合(例えば、メモリレイアウトが新しい形状と互換性がない場合)、代わりにコピーを返します。明示的にコピーを強制できます:
import numpy as np
original = np.arange(6)
reshaped_copy = original.reshape(2, 3).copy()
reshaped_copy[0, 0] = 999
print(original)
# [0 1 2 3 4 5] <-- 元の配列は影響を受けないreshapeがビューとコピーのどちらを返したかを確認するには、base属性を調べます:
import numpy as np
arr = np.arange(6)
view = arr.reshape(2, 3)
copy = arr.reshape(2, 3).copy()
print(view.base is arr) # True -- ビューです
print(copy.base is arr) # False -- コピーですよくあるエラーとその修正方法
エラー:"cannot reshape array of size X into shape Y"
これは最もよくあるreshapeエラーです。要素の総数が目標の形状と一致しない場合に発生します。
import numpy as np
arr = np.arange(10)
# 10 != 3 * 4 = 12 なので失敗
# arr.reshape(3, 4)
# ValueError: cannot reshape array of size 10 into shape (3,4)修正方法:
- 計算を確認してください。 すべての目標次元の積が
arr.sizeと等しいことを確認します。
import numpy as np
arr = np.arange(10)
print(arr.size) # 10
# 10要素の有効な形状: (2,5), (5,2), (1,10), (10,1), (10,)
print(arr.reshape(2, 5))
# [[0 1 2 3 4]
# [5 6 7 8 9]]- 配列をパディングまたはトリミングしてください。 均等に割り切れない形状が本当に必要な場合です。
import numpy as np
arr = np.arange(10)
# 12要素にパディングしてから(3, 4)にreshape
padded = np.pad(arr, (0, 2), constant_values=0)
print(padded.reshape(3, 4))
# [[0 1 2 3]
# [4 5 6 7]
# [8 9 0 0]]- -1を使用して NumPyに1つの次元を計算させ、手動計算のエラーを避けてください。
import numpy as np
arr = np.arange(10)
print(arr.reshape(-1, 2))
# [[0 1]
# [2 3]
# [4 5]
# [6 7]
# [8 9]]エラー:"Expected 2D array, got 1D array instead"
このscikit-learnエラーは、1Dの特徴量配列を渡した場合に表示されます。修正は簡単です:
import numpy as np
features = np.array([1.5, 2.3, 3.1, 4.7, 5.0])
# 列ベクトルに変換
features_2d = features.reshape(-1, 1)
print(features_2d.shape)
# (5, 1)実践的な例
Scikit-Learn用のデータ準備
scikit-learnは(n_samples, n_features)の形状の特徴量行列を期待します。単純な線形回帰のためにデータを正しくreshapeする方法は以下の通りです:
import numpy as np
# 単一の特徴量:住宅の面積(平方フィート)
sizes = np.array([850, 1200, 1500, 1800, 2100, 2400, 2800])
# sklearn用に(n_samples, 1)にreshape
X = sizes.reshape(-1, 1)
print(X.shape)
# (7, 1)
# 目的変数(価格)は既に1Dで、sklearnはこれを受け入れる
y = np.array([150000, 220000, 275000, 320000, 380000, 430000, 510000])
# Xとyはsklearnのための準備が整いました
# from sklearn.linear_model import LinearRegression
# model = LinearRegression().fit(X, y)画像データのreshape
画像データセットの操作では、フラットベクトルと空間次元の間のreshapeが頻繁に必要です:
import numpy as np
# 28x28グレースケール画像をフラット配列としてロードするシミュレーション(MNISTのように)
flat_image = np.random.randint(0, 256, size=784)
print(flat_image.shape)
# (784,)
# 2D画像にreshape
image_2d = flat_image.reshape(28, 28)
print(image_2d.shape)
# (28, 28)
# ニューラルネットワーク入力用に100枚の画像のバッチをreshape
batch_flat = np.random.randint(0, 256, size=(100, 784))
batch_images = batch_flat.reshape(100, 28, 28, 1) # チャンネル次元を追加
print(batch_images.shape)
# (100, 28, 28, 1)reshapeによる転置(そしてすべきでない理由)
よくある間違いは、reshapeを使って行列を「転置」しようとすることです。reshapeはメモリ順序で要素を並べ替えますが、これは転置とは異なります。
import numpy as np
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
# 間違い:reshape(3, 2)は転置しない
wrong = matrix.reshape(3, 2)
print("reshape(3,2):")
print(wrong)
# [[1 2]
# [3 4]
# [5 6]]
# 正しい:.Tまたはnp.transpose()を使用
correct = matrix.T
print("転置:")
print(correct)
# [[1 4]
# [2 5]
# [3 6]]RunCellでNumPy Reshapeを使う
配列を頻繁にreshapeし、より速いワークフローが必要な場合、RunCell (opens in a new tab)はJupyterノートブック内で動作するAIエージェントです。NumPy、pandas、scikit-learnのコードを毎日書くデータサイエンティスト向けに構築されています。
RunCellはreshape操作をいくつかの方法で支援できます:
- 形状デバッグの即時化。 形状の不一致エラーが発生した場合、RunCellはトレースバックを読み取り、正しい次元とorderパラメータを含む正しいreshape呼び出しを提案します。
- ボイラープレートの自動生成。 必要なものを自然言語で説明してください -- 「このフラット配列を3チャンネルの32x32画像のバッチにreshapeして」 -- するとRunCellがコードを書きます。
- 代替手段の探索。 RunCellは、あなたの具体的な状況に応じて、
reshape、np.expand_dims、np.newaxis、np.squeezeのどれを使うべきかを示してくれます。
RunCellはJupyter環境内で直接動作するため、データとコードの完全なコントロールを維持しながら、必要な場所でAIアシストの提案を受けることができます。
FAQ
numpy reshape(-1)は何をしますか?
array.reshape(-1)を呼び出すと、配列を1次元にフラット化します。-1はNumPyに要素の総数を自動的に計算するよう指示します。array.ravel()やarray.flatten()と同等ですが、reshape(-1)は可能な場合にビューを返し、flatten()は常にコピーを返します。
numpy reshapeは元の配列を変更しますか?
いいえ。reshape()は新しい配列オブジェクトを返します。ただし、返された配列がビュー(通常そうです)の場合、reshape後の配列を変更すると、同じメモリを共有しているため元の配列も変更されます。これを避けるには、結果に.copy()を呼び出してください。
reshapeとflattenの違いは何ですか?
reshape()は配列を任意の互換性のある形状に変換できます。flatten()は常に1D配列に変換し、常にコピーを返します。ravel()も1Dに変換しますが、reshape(-1)と同様に可能な場合はビューを返します。
pandas DataFrameをnumpy reshapeでreshapeできますか?
直接はできません。まずdf.valuesまたはdf.to_numpy()を使って基礎となるNumPy配列を抽出し、その後reshapeする必要があります。DataFrame固有のreshape操作には、pivot()、melt()、stack()、unstack()などのpandasメソッドを使用してください。
新しい軸を追加するために配列をreshapeするには?
reshape()を使用できますが、単一の次元を追加する場合はnp.expand_dims()やnp.newaxisの方がきれいです:
import numpy as np
arr = np.array([1, 2, 3])
# reshapeを使用
print(arr.reshape(1, 3).shape) # (1, 3)
print(arr.reshape(3, 1).shape) # (3, 1)
# np.newaxisを使用(より読みやすい)
print(arr[np.newaxis, :].shape) # (1, 3)
print(arr[:, np.newaxis].shape) # (3, 1)まとめ
numpy.reshape()はNumPyライブラリで最も頻繁に使用される関数の1つです。データをコピーせずに(ほとんどの場合)1D、2D、3D、およびそれ以上の次元の配列間で変換できます。覚えておくべきポイント:
- 要素の総数はreshape前後で同じでなければならない。
- 1つの次元に
-1を使用してNumPyに自動計算させる。 reshape()は通常コピーではなくビューを返す。ビューへの変更は元の配列に影響する。- デフォルトの
order='C'は行ごとに要素を埋める。MATLABやFortranの列優先データにはorder='F'を使用する。 - scikit-learnが1D配列について警告した場合、
.reshape(-1, 1)が解決策。
これらのパターンをマスターすれば、機械学習用の表形式データの準備やディープラーニング用の画像テンソルのreshapeなど、形状の不一致を自信を持って処理できるようになります。