NumPyを使ったデータ処理では、「複数の配列をまとめてひとつにしたい」場面がよくあります。
例えば、次のようなケースです:
- 2つの測定データを横に並べて分析したい
- 複数の画像データを縦方向に積み上げたい
- データとラベルを1つの行列に結合したい
この記事では、NumPy配列を結合するための主要関数と、それぞれの使い分け・注意点をわかりやすく説明します。
配列結合の基本概念

軸(axis)の理解
まず、結合を理解するために「軸(axis)」の概念を確認しましょう。
import numpy as np
# 2次元配列の例
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(f"配列の形状: {arr.shape}") # 結果: (2, 3)
print(f"axis=0の方向: 行方向(縦)、サイズ = {arr.shape[0]}") # 2
print(f"axis=1の方向: 列方向(横)、サイズ = {arr.shape[1]}") # 3
視覚的な理解:
axis=1(横方向)→
[1, 2, 3]
a [4, 5, 6]
x
i
s
=
0
(
縦
方
向
)
↓
np.concatenate():基本的な結合関数
基本構文
np.concatenate((配列1, 配列2), axis=軸)
axis=0
:縦に結合(行を増やす)axis=1
:横に結合(列を増やす)
例1:縦方向に結合(axis=0)
import numpy as np
# 2つの配列を準備
a = np.array([[1, 2],
[3, 4]])
b = np.array([[5, 6]])
print("配列a:")
print(a)
print(f"形状: {a.shape}") # 結果: (2, 2)
print("配列b:")
print(b)
print(f"形状: {b.shape}") # 結果: (1, 2)
# 縦方向に結合
result = np.concatenate((a, b), axis=0)
print("縦方向結合の結果:")
print(result)
# 結果:
# [[1 2]
# [3 4]
# [5 6]]
print(f"結合後の形状: {result.shape}") # 結果: (3, 2)
図解:
[1 2] [5 6] [1 2]
[3 4] + ↓ = [3 4]
↓ [5 6]
例2:横方向に結合(axis=1)
import numpy as np
a = np.array([[1, 2],
[3, 4]])
c = np.array([[7],
[8]])
print("配列a:")
print(a)
print(f"形状: {a.shape}") # 結果: (2, 2)
print("配列c:")
print(c)
print(f"形状: {c.shape}") # 結果: (2, 1)
# 横方向に結合
result = np.concatenate((a, c), axis=1)
print("横方向結合の結果:")
print(result)
# 結果:
# [[1 2 7]
# [3 4 8]]
print(f"結合後の形状: {result.shape}") # 結果: (2, 3)
図解:
[1 2] + [7] = [1 2 7]
[3 4] [8] [3 4 8]
→ →
重要な注意点:形状の一致
import numpy as np
# 形状が合わない例
a = np.array([[1, 2], [3, 4]]) # 形状: (2, 2)
d = np.array([[5, 6, 7]]) # 形状: (1, 3)
print(f"配列aの形状: {a.shape}")
print(f"配列dの形状: {d.shape}")
try:
# 縦方向結合を試すとエラー
result = np.concatenate((a, d), axis=0)
except ValueError as e:
print(f"エラー: {e}")
print("axis=0で結合するには、列数(axis=1のサイズ)が同じである必要があります")
try:
# 横方向結合を試すとエラー
result = np.concatenate((a, d), axis=1)
except ValueError as e:
print(f"エラー: {e}")
print("axis=1で結合するには、行数(axis=0のサイズ)が同じである必要があります")
複数の配列を一度に結合
import numpy as np
# 3つの配列を一度に結合
arr1 = np.array([[1, 2]])
arr2 = np.array([[3, 4]])
arr3 = np.array([[5, 6]])
# 複数配列の縦方向結合
result = np.concatenate((arr1, arr2, arr3), axis=0)
print("3つの配列を縦方向に結合:")
print(result)
# 結果:
# [[1 2]
# [3 4]
# [5 6]]
まとめ
concatenate()
は最も汎用的な結合方法- 軸(axis)と形状をきちんと揃える必要がある
np.vstack() / np.hstack():軸を意識せず簡単に使える

vstack():縦に積む(vertical stack)
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
# vstackを使用(axis=0のconcatenateと同じ)
result_vstack = np.vstack((a, b))
print("vstackの結果:")
print(result_vstack)
# 結果:
# [[1 2]
# [3 4]
# [5 6]]
# concatenateと同じ結果
result_concat = np.concatenate((a, b), axis=0)
print("concatenate(axis=0)と同じ:", np.array_equal(result_vstack, result_concat))
hstack():横に積む(horizontal stack)
import numpy as np
a = np.array([[1, 2], [3, 4]])
c = np.array([[7], [8]])
# hstackを使用(axis=1のconcatenateと同じ)
result_hstack = np.hstack((a, c))
print("hstackの結果:")
print(result_hstack)
# 結果:
# [[1 2 7]
# [3 4 8]]
# concatenateと同じ結果
result_concat = np.concatenate((a, c), axis=1)
print("concatenate(axis=1)と同じ:", np.array_equal(result_hstack, result_concat))
1次元配列での使用例
import numpy as np
# 1次元配列の場合
vec1 = np.array([1, 2, 3])
vec2 = np.array([4, 5, 6])
print("1次元配列:")
print(f"vec1: {vec1}, 形状: {vec1.shape}")
print(f"vec2: {vec2}, 形状: {vec2.shape}")
# vstackで縦に積む
vertical = np.vstack((vec1, vec2))
print("vstack結果:")
print(vertical)
# 結果:
# [[1 2 3]
# [4 5 6]]
print(f"形状: {vertical.shape}") # 結果: (2, 3)
# hstackで横に連結
horizontal = np.hstack((vec1, vec2))
print("hstack結果:")
print(horizontal) # 結果: [1 2 3 4 5 6]
print(f"形状: {horizontal.shape}") # 結果: (6,)
関数の特徴と制限
関数 | 結合方向 | 条件 | 使いやすさ |
---|---|---|---|
vstack() | axis=0(縦) | 列数が同じであること | 高 |
hstack() | axis=1(横) | 行数が同じであること | 高 |
concatenate() | 指定可能 | 指定軸以外の形状が同じ | 中(柔軟性高) |
まとめ
vstack/hstack
は簡単に使えるショートカット関数- よく使う縦・横結合を直感的に表現
np.stack():新たな次元で結合したいとき
基本概念
stack()
は、同じ形状の配列を新しい次元で結合する関数です。
import numpy as np
# 同じ形状の2つの配列
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print("配列a:")
print(a)
print(f"形状: {a.shape}") # 結果: (2, 2)
print("配列b:")
print(b)
print(f"形状: {b.shape}") # 結果: (2, 2)
axis=0での結合(新しい軸を先頭に追加)
# 新しい次元で結合
result = np.stack((a, b), axis=0)
print("stack(axis=0)の結果:")
print(result)
# 結果:
# [[[1 2]
# [3 4]]
# [[5 6]
# [7 8]]]
print(f"結合後の形状: {result.shape}") # 結果: (2, 2, 2)
# アクセス方法
print(f"1つ目の配列: \n{result[0]}") # aと同じ
print(f"2つ目の配列: \n{result[1]}") # bと同じ
axis=1での結合(中間に新しい軸を追加)
result_axis1 = np.stack((a, b), axis=1)
print("stack(axis=1)の結果:")
print(result_axis1)
# 結果:
# [[[1 2]
# [5 6]]
# [[3 4]
# [7 8]]]
print(f"結合後の形状: {result_axis1.shape}") # 結果: (2, 2, 2)
axis=-1での結合(末尾に新しい軸を追加)
result_axis_last = np.stack((a, b), axis=-1)
print("stack(axis=-1)の結果:")
print(result_axis_last)
# 結果:
# [[[1 5]
# [2 6]]
# [[3 7]
# [4 8]]]
print(f"結合後の形状: {result_axis_last.shape}") # 結果: (2, 2, 2)
実用例1:画像データのバッチ化
import numpy as np
# 3枚の28×28画像
image1 = np.random.rand(28, 28)
image2 = np.random.rand(28, 28)
image3 = np.random.rand(28, 28)
print(f"各画像の形状: {image1.shape}") # 結果: (28, 28)
# バッチとして結合
batch_images = np.stack((image1, image2, image3), axis=0)
print(f"バッチ化後の形状: {batch_images.shape}") # 結果: (3, 28, 28)
# 機械学習で使いやすい形式
print("バッチの各画像にアクセス:")
print(f"1枚目の形状: {batch_images[0].shape}")
print(f"2枚目の形状: {batch_images[1].shape}")
print(f"3枚目の形状: {batch_images[2].shape}")
実用例2:時系列データのチャンネル追加
import numpy as np
# 3つの異なるセンサーの時系列データ
sensor1 = np.random.randn(100) # 100時点のデータ
sensor2 = np.random.randn(100)
sensor3 = np.random.randn(100)
print(f"各センサーデータの形状: {sensor1.shape}") # 結果: (100,)
# チャンネル次元で結合
multi_channel = np.stack((sensor1, sensor2, sensor3), axis=1)
print(f"マルチチャンネルデータの形状: {multi_channel.shape}") # 結果: (100, 3)
# 時系列分析で使いやすい形式(時刻×チャンネル)
print("各時刻のデータ例:")
print(f"時刻0: {multi_channel[0]}") # 3つのセンサーの値
print(f"時刻1: {multi_channel[1]}")
注意:形状が完全一致している必要がある
import numpy as np
# 形状が異なる配列
arr1 = np.array([[1, 2], [3, 4]]) # 形状: (2, 2)
arr2 = np.array([[5, 6, 7], [8, 9, 10]]) # 形状: (2, 3)
try:
result = np.stack((arr1, arr2), axis=0)
except ValueError as e:
print(f"エラー: {e}")
print("stackは完全に同じ形状の配列でないと使用できません")
まとめ
stack()
は「次元を増やして結合」したいときに使う- 全ての配列の形状が完全一致している必要がある
- バッチ処理やマルチチャンネルデータの作成に便利
形が合わないときの対処法

問題:形状の不一致
import numpy as np
# 形状が合わない配列の例
x = np.array([1, 2, 3]) # 形状: (3,)
y = np.array([[4], [5], [6]]) # 形状: (3, 1)
print(f"配列x: {x}, 形状: {x.shape}")
print(f"配列y: \n{y}\n形状: {y.shape}")
try:
result = np.hstack((x, y))
except ValueError as e:
print(f"エラー: {e}")
print("形状が合わないため結合できません")
解決方法1:reshapeやnewaxisで形を揃える
import numpy as np
x = np.array([1, 2, 3])
y = np.array([[4], [5], [6]])
# 方法1: reshapeを使用
x_reshaped = x.reshape(-1, 1) # (3,) → (3, 1)
print(f"reshapeしたx: \n{x_reshaped}\n形状: {x_reshaped.shape}")
result1 = np.hstack((x_reshaped, y))
print(f"結合結果1: \n{result1}")
# 方法2: newaxisを使用
x_newaxis = x[:, np.newaxis] # (3,) → (3, 1)
print(f"newaxisを使ったx: \n{x_newaxis}\n形状: {x_newaxis.shape}")
result2 = np.hstack((x_newaxis, y))
print(f"結合結果2: \n{result2}")
# 結果は同じ
print(f"結果が同じ: {np.array_equal(result1, result2)}")
解決方法2:broadcast可能な形状に調整
import numpy as np
# 異なるサイズの配列
a = np.array([1, 2, 3]) # 形状: (3,)
b = np.array([4, 5]) # 形状: (2,)
print(f"配列a: {a}")
print(f"配列b: {b}")
# tileを使って同じ長さに揃える
# bを3つに拡張
b_extended = np.tile(b, (2,))[:3] # [4, 5, 4]の最初の3要素
print(f"拡張したb: {b_extended}")
# 結合
result = np.vstack((a, b_extended))
print(f"結合結果: \n{result}")
解決方法3:パディング(ゼロ埋め)
import numpy as np
# 長さが異なる配列
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5])
# 短い方にゼロを追加
max_length = max(len(arr1), len(arr2))
arr1_padded = np.pad(arr1, (0, max_length - len(arr1)), constant_values=0)
arr2_padded = np.pad(arr2, (0, max_length - len(arr2)), constant_values=0)
print(f"パディング後のarr1: {arr1_padded}")
print(f"パディング後のarr2: {arr2_padded}")
# 結合
result = np.vstack((arr1_padded, arr2_padded))
print(f"結合結果: \n{result}")
実用的な形状調整関数
import numpy as np
def smart_concatenate(arrays, axis=0, fill_value=0):
"""
形状を自動調整して配列を結合する関数
"""
if axis == 0: # 縦方向結合
# 最大列数に合わせる
max_cols = max(arr.shape[-1] if arr.ndim > 1 else 1 for arr in arrays)
adjusted_arrays = []
for arr in arrays:
if arr.ndim == 1:
arr = arr.reshape(1, -1)
if arr.shape[1] < max_cols:
padding = max_cols - arr.shape[1]
arr = np.pad(arr, ((0, 0), (0, padding)), constant_values=fill_value)
adjusted_arrays.append(arr)
return np.concatenate(adjusted_arrays, axis=0)
elif axis == 1: # 横方向結合
# 最大行数に合わせる
max_rows = max(arr.shape[0] if arr.ndim > 1 else len(arr) for arr in arrays)
adjusted_arrays = []
for arr in arrays:
if arr.ndim == 1:
arr = arr.reshape(-1, 1)
if arr.shape[0] < max_rows:
padding = max_rows - arr.shape[0]
arr = np.pad(arr, ((0, padding), (0, 0)), constant_values=fill_value)
adjusted_arrays.append(arr)
return np.concatenate(adjusted_arrays, axis=1)
# 使用例
arr1 = np.array([1, 2, 3])
arr2 = np.array([[4, 5], [6, 7]])
arr3 = np.array([8])
result = smart_concatenate([arr1, arr2, arr3], axis=0, fill_value=0)
print("スマート結合の結果:")
print(result)
その他の便利な結合関数
np.r_[]とnp.c_[]:簡潔な記法
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# r_[]:行方向(縦)の結合
result_r = np.r_[a, b]
print(f"r_[]での結合: {result_r}") # 結果: [1 2 3 4 5 6]
# c_[]:列方向の結合(2次元化)
result_c = np.c_[a, b]
print(f"c_[]での結合: \n{result_c}")
# 結果:
# [[1 4]
# [2 5]
# [3 6]]
np.append():要素やサブ配列の追加
import numpy as np
# 基本的な使用
arr = np.array([1, 2, 3])
result = np.append(arr, [4, 5])
print(f"append結果: {result}") # 結果: [1 2 3 4 5]
# 2次元配列での使用
matrix = np.array([[1, 2], [3, 4]])
new_row = np.array([[5, 6]])
# 行を追加
result_row = np.append(matrix, new_row, axis=0)
print(f"行追加: \n{result_row}")
# 列を追加
new_col = np.array([[7], [8]])
result_col = np.append(matrix, new_col, axis=1)
print(f"列追加: \n{result_col}")
実用的な使用例
例1:データ分析での結合
import numpy as np
# 異なる実験条件のデータ
condition_A = np.random.randn(50, 3) # 50サンプル、3特徴量
condition_B = np.random.randn(75, 3) # 75サンプル、3特徴量
condition_C = np.random.randn(25, 3) # 25サンプル、3特徴量
print(f"条件A: {condition_A.shape}")
print(f"条件B: {condition_B.shape}")
print(f"条件C: {condition_C.shape}")
# 全データを結合
all_data = np.vstack((condition_A, condition_B, condition_C))
print(f"結合後のデータ: {all_data.shape}") # 結果: (150, 3)
# ラベルも作成
labels_A = np.full(50, 0) # 条件Aは0
labels_B = np.full(75, 1) # 条件Bは1
labels_C = np.full(25, 2) # 条件Cは2
all_labels = np.hstack((labels_A, labels_B, labels_C))
print(f"ラベル: {all_labels.shape}") # 結果: (150,)
# データとラベルを横に結合
dataset = np.c_[all_data, all_labels]
print(f"最終データセット: {dataset.shape}") # 結果: (150, 4)
例2:画像処理での結合
import numpy as np
# 異なるサイズの画像を処理
image1 = np.random.rand(64, 64) # 64×64
image2 = np.random.rand(64, 128) # 64×128
image3 = np.random.rand(64, 32) # 64×32
print(f"画像1: {image1.shape}")
print(f"画像2: {image2.shape}")
print(f"画像3: {image3.shape}")
# 横に並べて表示用に結合
combined_width = image1.shape[1] + image2.shape[1] + image3.shape[1]
combined_image = np.zeros((64, combined_width))
# 順番に配置
start_col = 0
combined_image[:, start_col:start_col + image1.shape[1]] = image1
start_col += image1.shape[1]
combined_image[:, start_col:start_col + image2.shape[1]] = image2
start_col += image2.shape[1]
combined_image[:, start_col:start_col + image3.shape[1]] = image3
print(f"結合画像: {combined_image.shape}") # 結果: (64, 224)
例3:時系列データの結合
import numpy as np
# 異なる期間の時系列データ
daily_data = np.random.randn(365, 4) # 1年間の日次データ(4変数)
hourly_data = np.random.randn(24, 4) # 1日分の時間データ(4変数)
print(f"日次データ: {daily_data.shape}")
print(f"時間データ: {hourly_data.shape}")
# 日次データに時間データを追加
extended_data = np.vstack((daily_data, hourly_data))
print(f"拡張データ: {extended_data.shape}") # 結果: (389, 4)
# 新しい特徴量を追加
temperature = np.random.randn(389, 1)
humidity = np.random.randn(389, 1)
# 横方向に特徴量を追加
full_dataset = np.hstack((extended_data, temperature, humidity))
print(f"完全データセット: {full_dataset.shape}") # 結果: (389, 6)
結合関数のまとめ表

関数 | 特徴 | 注意点 | よく使う場面 |
---|---|---|---|
concatenate() | 最も汎用的、軸指定可能 | axis指定・形状を揃える | 柔軟な結合が必要 |
vstack() | 縦方向結合、直感的 | 列数を揃える | データの追加 |
hstack() | 横方向結合、直感的 | 行数を揃える | 特徴量の追加 |
stack() | 新次元で結合 | 全体形状が完全一致 | バッチ化、チャンネル結合 |
append() | 要素追加、配列追加 | 新しい配列を返す | 動的なデータ追加 |
r_[] | 行方向の簡潔記法 | 1次元のみ | 簡単な連結 |
c_[] | 列方向の簡潔記法 | 自動的に2次元化 | 列ベクトルの結合 |
まとめ
結合したい形 | おすすめ関数 | 備考 |
---|---|---|
単純な上下連結 | vstack() または concatenate(axis=0) | 列数を揃える |
横方向に連結 | hstack() または concatenate(axis=1) | 行数を揃える |
次元を増やしたい | stack() | 完全同一形状が必要 |
柔軟な結合 | concatenate() | axisで方向指定 |
簡単な連結 | r_[] または c_[] | 記法が簡潔 |
コメント