NumPy配列(ndarray)は次元(軸の数)によって構造が決まります。
しかし、実際のデータ処理では「1次元を2次元にしたい」「余分な軸を削りたい」といった、柔軟な次元の操作が必要になります。
この記事では、次元の追加・削除の方法を中心に、reshapeとは異なる次元制御を、具体例とともに説明していきます。
次元の基本概念を理解しよう

次元(軸)とは何か?
import numpy as np
# 1次元配列(軸が1つ)
arr_1d = np.array([1, 2, 3])
print(f"1次元配列: {arr_1d}")
print(f"形状: {arr_1d.shape}") # 結果: (3,)
print(f"次元数: {arr_1d.ndim}") # 結果: 1
# 2次元配列(軸が2つ)
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print(f"2次元配列:")
print(arr_2d)
print(f"形状: {arr_2d.shape}") # 結果: (2, 3)
print(f"次元数: {arr_2d.ndim}") # 結果: 2
# 3次元配列(軸が3つ)
arr_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(f"3次元配列:")
print(arr_3d)
print(f"形状: {arr_3d.shape}") # 結果: (2, 2, 2)
print(f"次元数: {arr_3d.ndim}") # 結果: 3
なぜ次元操作が必要?
実際の例:
- 機械学習で「1枚の画像」を「バッチ(複数画像)」として扱いたい
- 計算結果の「余分な次元」を削除してすっきりさせたい
- 行列計算で形状を合わせたい
次元を追加する方法
方法1:np.newaxisを使用
np.newaxis
は、配列に新しい軸を追加する最も簡単な方法です。
1次元から2次元(列ベクトル化)
import numpy as np
# 1次元配列
a = np.array([1, 2, 3])
print(f"元の配列: {a}")
print(f"元の形状: {a.shape}") # 結果: (3,)
# 列ベクトル(縦に並べる)に変換
a_col = a[:, np.newaxis]
print(f"列ベクトル:")
print(a_col)
# 結果:
# [[1]
# [2]
# [3]]
print(f"列ベクトルの形状: {a_col.shape}") # 結果: (3, 1)
1次元から2次元(行ベクトル化)
# 行ベクトル(横に並べる)に変換
a_row = a[np.newaxis, :]
print(f"行ベクトル: {a_row}") # 結果: [[1 2 3]]
print(f"行ベクトルの形状: {a_row.shape}") # 結果: (1, 3)
実用的な例:複数の場所に軸を追加
# 元の配列
arr = np.array([1, 2, 3, 4])
print(f"元: {arr.shape}") # 結果: (4,)
# 先頭に軸を追加
arr_front = arr[np.newaxis, :]
print(f"先頭に追加: {arr_front.shape}") # 結果: (1, 4)
# 末尾に軸を追加
arr_end = arr[:, np.newaxis]
print(f"末尾に追加: {arr_end.shape}") # 結果: (4, 1)
# 中間に軸を追加(3次元になる)
arr_2d = arr.reshape(2, 2) # まず2次元にする
arr_middle = arr_2d[:, np.newaxis, :]
print(f"中間に追加: {arr_middle.shape}") # 結果: (2, 1, 2)
方法2:np.expand_dims()を使用
expand_dims()
は、軸の位置を数値で指定できるより汎用的な方法です。
import numpy as np
a = np.array([1, 2, 3])
print(f"元の配列: {a}")
print(f"元の形状: {a.shape}") # 結果: (3,)
# axis=0: 先頭に軸を追加
expanded_0 = np.expand_dims(a, axis=0)
print(f"axis=0で追加: {expanded_0}") # 結果: [[1 2 3]]
print(f"形状: {expanded_0.shape}") # 結果: (1, 3)
# axis=1: 末尾に軸を追加
expanded_1 = np.expand_dims(a, axis=1)
print(f"axis=1で追加:")
print(expanded_1)
# 結果:
# [[1]
# [2]
# [3]]
print(f"形状: {expanded_1.shape}") # 結果: (3, 1)
# axis=-1: 最後に軸を追加(axis=1と同じ)
expanded_last = np.expand_dims(a, axis=-1)
print(f"axis=-1で追加の形状: {expanded_last.shape}") # 結果: (3, 1)
複数次元での軸追加
# 2次元配列に軸を追加
matrix = np.array([[1, 2], [3, 4]])
print(f"元の2次元配列:")
print(matrix)
print(f"形状: {matrix.shape}") # 結果: (2, 2)
# さまざまな位置に軸を追加
expanded_0 = np.expand_dims(matrix, axis=0) # 形状: (1, 2, 2)
expanded_1 = np.expand_dims(matrix, axis=1) # 形状: (2, 1, 2)
expanded_2 = np.expand_dims(matrix, axis=2) # 形状: (2, 2, 1)
print(f"axis=0: {expanded_0.shape}")
print(f"axis=1: {expanded_1.shape}")
print(f"axis=2: {expanded_2.shape}")
実用例:画像処理でバッチ次元を追加
import numpy as np
# 単一の画像(28×28ピクセル)
image = np.random.rand(28, 28)
print(f"単一画像の形状: {image.shape}") # 結果: (28, 28)
# バッチ次元を追加(機械学習モデルの入力形式)
# 方法1: newaxisを使用
batch_image_1 = image[np.newaxis, :, :]
print(f"バッチ化(方法1): {batch_image_1.shape}") # 結果: (1, 28, 28)
# 方法2: expand_dimsを使用
batch_image_2 = np.expand_dims(image, axis=0)
print(f"バッチ化(方法2): {batch_image_2.shape}") # 結果: (1, 28, 28)
# カラー画像の場合(チャンネル次元も追加)
color_image = np.random.rand(28, 28, 3) # RGB画像
batch_color = np.expand_dims(color_image, axis=0)
print(f"カラー画像のバッチ化: {batch_color.shape}") # 結果: (1, 28, 28, 3)
まとめ
np.newaxis
:シンプルで直感的expand_dims()
:軸の位置を数値で指定、より汎用的
次元を削除する方法

np.squeeze()の基本
squeeze()
は、サイズが1の軸を削除する関数です。
import numpy as np
# サイズ1の軸を持つ配列
b = np.array([[[1], [2], [3]]])
print(f"元の配列:")
print(b)
print(f"元の形状: {b.shape}") # 結果: (1, 3, 1)
# 全てのサイズ1の軸を削除
b_squeezed = np.squeeze(b)
print(f"squeeze後: {b_squeezed}") # 結果: [1 2 3]
print(f"squeeze後の形状: {b_squeezed.shape}") # 結果: (3,)
特定の軸だけ削除
import numpy as np
# 複数のサイズ1軸を持つ配列
arr = np.array([[[[1, 2, 3]]]])
print(f"元の形状: {arr.shape}") # 結果: (1, 1, 1, 3)
# 特定の軸だけ削除
squeezed_axis0 = np.squeeze(arr, axis=0)
print(f"axis=0を削除: {squeezed_axis0.shape}") # 結果: (1, 1, 3)
squeezed_axis1 = np.squeeze(arr, axis=1)
print(f"axis=1を削除: {squeezed_axis1.shape}") # 結果: (1, 1, 3)
# 複数の軸を同時に削除
squeezed_multiple = np.squeeze(arr, axis=(0, 1))
print(f"axis=0,1を削除: {squeezed_multiple.shape}") # 結果: (1, 3)
注意点:指定した軸がサイズ1でない場合
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]]) # 形状: (2, 3)
print(f"元の形状: {arr.shape}")
try:
# axis=0はサイズ2なので削除できない
squeezed = np.squeeze(arr, axis=0)
except ValueError as e:
print(f"エラー: {e}")
print("サイズ1でない軸は削除できません")
# 安全な使い方:軸を指定しない
squeezed_safe = np.squeeze(arr)
print(f"安全なsqueeze: {squeezed_safe.shape}") # 結果: (2, 3) ← 変化なし
実用例:モデル出力の整形
import numpy as np
# 機械学習モデルの出力(バッチサイズ1の予測結果)
model_output = np.array([[0.1, 0.9]])
print(f"モデル出力の形状: {model_output.shape}") # 結果: (1, 2)
# バッチ次元を削除
prediction = np.squeeze(model_output)
print(f"予測結果: {prediction}") # 結果: [0.1 0.9]
print(f"整形後の形状: {prediction.shape}") # 結果: (2,)
# 特定の軸だけ削除する場合
prediction_axis0 = np.squeeze(model_output, axis=0)
print(f"axis=0のみ削除: {prediction_axis0.shape}") # 結果: (2,)
注意:意図しない軸まで削除される場合
import numpy as np
# 画像データ(1枚、28×28、グレースケール)
image = np.ones((1, 28, 28, 1))
print(f"元の画像形状: {image.shape}") # 結果: (1, 28, 28, 1)
# 全てのサイズ1軸を削除(注意!)
squeezed_all = np.squeeze(image)
print(f"全削除後: {squeezed_all.shape}") # 結果: (28, 28)
# バッチ次元だけ削除したい場合
squeezed_batch = np.squeeze(image, axis=0)
print(f"バッチ次元のみ削除: {squeezed_batch.shape}") # 結果: (28, 28, 1)
# チャンネル次元だけ削除したい場合
squeezed_channel = np.squeeze(image, axis=-1)
print(f"チャンネル次元のみ削除: {squeezed_channel.shape}") # 結果: (1, 28, 28)
まとめ
squeeze()
は不要な「サイズ1の軸」を削除してシンプルにできる- 軸を指定しないと全てのサイズ1軸が削除される
- 特定の軸だけ削除したい場合は
axis
パラメータを使用
reshapeとの違い
操作 | reshape | newaxis / squeeze |
---|---|---|
対象 | 要素数を保ち全体を再構成 | 軸の追加・削除に特化 |
柔軟性 | 高いが構造が大きく変わる | 指定軸のみ変更で安全 |
よく使う場面 | データの構造変更 | 行列→ベクトル、バッチ処理など |
要素の順序 | 変わる可能性がある | 変わらない |
具体的な比較例
import numpy as np
# 元の配列
arr = np.array([1, 2, 3, 4, 5, 6])
print(f"元の配列: {arr}")
print(f"元の形状: {arr.shape}") # 結果: (6,)
# reshape:要素の並び方が変わる
reshaped = arr.reshape(2, 3)
print("reshapeの結果:")
print(reshaped)
# 結果:
# [[1 2 3]
# [4 5 6]]
# newaxis:要素の並び方は変わらない
newaxis_result = arr[:, np.newaxis]
print("newaxisの結果:")
print(newaxis_result)
# 結果:
# [[1]
# [2]
# [3]
# [4]
# [5]
# [6]]
print(f"reshape後: {reshaped.shape}") # 結果: (2, 3)
print(f"newaxis後: {newaxis_result.shape}") # 結果: (6, 1)
実務での活用例

活用例1:機械学習でのバッチ処理
import numpy as np
# 単一サンプルの特徴量
single_sample = np.array([0.5, 1.2, -0.3, 0.8])
print(f"単一サンプル: {single_sample.shape}") # 結果: (4,)
# バッチ処理のため次元を追加
batch_sample = np.expand_dims(single_sample, axis=0)
print(f"バッチ化: {batch_sample.shape}") # 結果: (1, 4)
# モデルで予測(仮の処理)
prediction = batch_sample * 2 # 仮の計算
print(f"予測結果: {prediction.shape}") # 結果: (1, 4)
# 結果から余分な次元を削除
final_result = np.squeeze(prediction)
print(f"最終結果: {final_result}") # 結果: [1. 2.4 -0.6 1.6]
print(f"最終形状: {final_result.shape}") # 結果: (4,)
活用例2:画像処理でのチャンネル操作
import numpy as np
# グレースケール画像(高さ×幅)
gray_image = np.random.rand(100, 100)
print(f"グレースケール: {gray_image.shape}") # 結果: (100, 100)
# チャンネル次元を追加(多くのライブラリが期待する形式)
gray_with_channel = np.expand_dims(gray_image, axis=-1)
print(f"チャンネル追加: {gray_with_channel.shape}") # 結果: (100, 100, 1)
# RGB画像に変換(グレースケールを3回繰り返し)
rgb_image = np.repeat(gray_with_channel, 3, axis=-1)
print(f"RGB変換: {rgb_image.shape}") # 結果: (100, 100, 3)
# 処理後、元のグレースケールに戻す
back_to_gray = rgb_image[:, :, 0] # R成分だけ取得
print(f"グレースケールに戻す: {back_to_gray.shape}") # 結果: (100, 100)
活用例3:時系列データの処理
import numpy as np
# 1次元の時系列データ
time_series = np.random.randn(100) # 100時点のデータ
print(f"時系列データ: {time_series.shape}") # 結果: (100,)
# RNN用に3次元にする(バッチ、時刻、特徴量)
# バッチ次元を追加
batch_time_series = np.expand_dims(time_series, axis=0)
print(f"バッチ次元追加: {batch_time_series.shape}") # 結果: (1, 100)
# 特徴量次元を追加
rnn_input = np.expand_dims(batch_time_series, axis=-1)
print(f"RNN入力形式: {rnn_input.shape}") # 結果: (1, 100, 1)
# RNN処理後(仮の出力)
rnn_output = rnn_input * 2 # 仮の処理
print(f"RNN出力: {rnn_output.shape}") # 結果: (1, 100, 1)
# 結果を1次元に戻す
final_output = np.squeeze(rnn_output)
print(f"最終出力: {final_output.shape}") # 結果: (100,)
活用例4:行列計算での形状合わせ
import numpy as np
# ベクトルと行列の計算
vector = np.array([1, 2, 3]) # 形状: (3,)
matrix = np.array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]) # 形状: (3, 3)
print(f"ベクトル: {vector.shape}")
print(f"行列: {matrix.shape}")
# 内積計算(正常に動作)
dot_product = vector @ matrix
print(f"内積結果: {dot_product}") # 結果: [1 2 3]
# ベクトルを列ベクトルにして行列計算
col_vector = vector[:, np.newaxis] # 形状: (3, 1)
matrix_mult = matrix @ col_vector
print(f"行列×列ベクトル:")
print(matrix_mult)
# 結果:
# [[1]
# [2]
# [3]]
# 結果を1次元に戻す
result_1d = np.squeeze(matrix_mult)
print(f"1次元に戻した結果: {result_1d}") # 結果: [1 2 3]
便利な組み合わせテクニック
複数の軸操作を組み合わせ
import numpy as np
# 1次元データから複雑な形状を作成
data = np.arange(24)
print(f"元データ: {data.shape}") # 結果: (24,)
# 段階的に次元を追加
step1 = np.expand_dims(data, axis=0) # 形状: (1, 24)
step2 = np.expand_dims(step1, axis=-1) # 形状: (1, 24, 1)
step3 = step2.reshape(1, 6, 4, 1) # 形状: (1, 6, 4, 1)
print(f"最終形状: {step3.shape}")
# 特定の軸だけ削除
step4 = np.squeeze(step3, axis=0) # 形状: (6, 4, 1)
step5 = np.squeeze(step4, axis=-1) # 形状: (6, 4)
print(f"簡略化後: {step5.shape}")
条件付き次元操作
import numpy as np
def smart_squeeze(arr, target_dims=2):
"""指定した次元数になるまでsqueezeする関数"""
while arr.ndim > target_dims:
# サイズ1の軸があれば削除
size_1_axes = [i for i, size in enumerate(arr.shape) if size == 1]
if size_1_axes:
arr = np.squeeze(arr, axis=size_1_axes[0])
else:
break
return arr
# 使用例
complex_array = np.ones((1, 1, 5, 1, 3, 1))
print(f"元の形状: {complex_array.shape}") # 結果: (1, 1, 5, 1, 3, 1)
simplified = smart_squeeze(complex_array, target_dims=2)
print(f"簡略化後: {simplified.shape}") # 結果: (5, 3)
まとめ
操作内容 | 方法 | 使う場面 |
---|---|---|
次元を追加 | np.newaxis , expand_dims() | バッチ処理、行列計算の形状合わせ |
次元を削除 | np.squeeze() | 余分な軸の削除、結果の簡略化 |
安全な軸指定 | axis パラメータ使用 | 特定の軸のみ操作したい場合 |
全体構造変更 | reshape() | データの根本的な再構成 |
トラブルシューティング
よくあるエラーと対処法
import numpy as np
# エラー1: squeeze時に対象軸がサイズ1でない
arr = np.array([[1, 2, 3], [4, 5, 6]])
try:
np.squeeze(arr, axis=0) # axis=0はサイズ2
except ValueError:
print("解決策: 軸を指定せずsqueeze()を使うか、正しい軸を指定")
# エラー2: expand_dimsで無効な軸を指定
try:
np.expand_dims(arr, axis=3) # 2次元配列に軸3は存在しない
except np.AxisError:
print("解決策: 有効な軸番号を指定(-1〜ndimの範囲)")
# 安全な次元操作の確認
def safe_dimension_check(arr, operation=""):
print(f"{operation}前: 形状={arr.shape}, 次元数={arr.ndim}")
return arr
# 使用例
test_arr = np.array([1, 2, 3])
test_arr = safe_dimension_check(test_arr, "expand_dims")
expanded = np.expand_dims(test_arr, axis=0)
expanded = safe_dimension_check(expanded, "expand_dims")
コメント