Pythonを用いたデータ分析や機械学習の現場において、NumPy配列(ndarray)の操作は避けては通れない基本的なスキルです。
特に複数のデータソースを統合したり、計算結果を一つの行列にまとめたりする際には、配列の結合操作が頻繁に発生します。
NumPyには配列を結合するための関数がいくつか用意されていますが、その中でも直感的で使いやすいのがvstackとhstackです。
本記事では、これら二つの関数の基本的な使い方から、実務で役立つ実践的なテクニック、さらにはエラーを回避するための注意点まで詳しく解説します。
配列操作の基礎を固めることで、より複雑なデータ処理を効率的に実装できるようになるでしょう。
なぜNumPy配列の結合が重要なのか
データサイエンスのプロジェクトでは、データは常に整理された状態で提供されるわけではありません。
異なるタイミングで収集されたデータや、複数の特徴量を個別に計算した結果を、一つの学習用データセットとして統合する必要があります。
NumPy配列は固定長でメモリ上に配置されるため、Pythonの標準リストのように要素を一つずつ追加していく操作は効率が良くありません。
そのため、既存の配列を効率よく結合する専用の関数を理解し、適切に使い分けることがパフォーマンスの向上に直結します。
大規模なデータを扱う際には、結合時のコピーコストや次元の整合性を意識することが非常に重要です。
vstackとhstackをマスターすることは、NumPyを使いこなすための第一歩と言えるでしょう。
垂直方向に積み上げるnp.vstackの使い方
np.vstackは、名前の通り配列を「垂直方向(Vertical)」に積み上げるための関数です。
数学的な行列のイメージでは、行(Row)を追加していく操作に相当します。
この関数は、引数として結合したい配列をタプルやリストの形式で受け取ります。
基本的な1次元配列の垂直結合
まずは、最もシンプルな1次元配列同士の結合について見ていきましょう。
1次元配列をnp.vstackで結合すると、それぞれの配列が新しい行列の「行」として配置され、2次元配列が生成されます。
import numpy as np
# 1次元配列の定義
array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])
# 垂直方向に結合
result = np.vstack((array1, array2))
print(result)
print("形状:", result.shape)
[[1 2 3]
[4 5 6]]
形状: (2, 3)
このように、元の配列が1次元であっても、結合後は2次元配列になるという点が大きな特徴です。
2次元配列同士の垂直結合
実務でより多く利用されるのは、2次元配列(行列)同士の結合です。
既存の行列に対して、新しいデータサンプル(行)を追加する場合などに重宝します。
# 2次元配列の定義
matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6]])
# 垂直方向に結合
result_matrix = np.vstack((matrix1, matrix2))
print(result_matrix)
[[1 2]
[3 4]
[5 6]]
このとき、結合する配列の「列数」が一致していなければならないという制約に注意してください。
列数が異なる配列をnp.vstackで結合しようとすると、ValueErrorが発生します。
水平方向に並べるnp.hstackの使い方
次に、配列を「水平方向(Horizontal)」に並べるnp.hstackについて解説します。
これは行列に対して列(Column)を追加していく操作、あるいは横に連結していく操作に相当します。
特徴量の追加や、時系列データの連結などで頻繁に使用されます。
1次元配列の水平結合
1次元配列をnp.hstackで結合した場合、np.vstackとは異なり、単純に要素が横に並んだ1次元配列が返されます。
# 1次元配列の定義
array_a = np.array([1, 2, 3])
array_b = np.array([4, 5, 6])
# 水平方向に結合
result_h = np.hstack((array_a, array_b))
print(result_h)
print("形状:", result_h.shape)
[1 2 3 4 5 6]
形状: (6,)
このように、1次元配列同士を結合しても次元が増えることはありません。
2次元配列同士の水平結合
2次元配列の場合、np.hstackは各行の右側に新しい要素を継ぎ足す動きをします。
# 2次元配列の定義
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
# 水平方向に結合
result_matrix_h = np.hstack((matrix_a, matrix_b))
print(result_matrix_h)
[[1 2 5 6]
[3 4 7 8]]
この場合、結合する配列の「行数」が一致していることが必要です。
サンプル数が同じで、異なる特徴量を持つ二つのデータセットを統合する際などに非常に便利です。
vstackとhstackの使い分けと違いのまとめ
二つの関数の違いを正しく理解するために、主要なポイントを表にまとめました。
| 関数名 | 結合方向 | 1次元配列の結合結果 | 必須条件 |
|---|---|---|---|
np.vstack | 垂直 (行方向) | 2次元配列になる | 列数が一致していること |
np.hstack | 水平 (列方向) | 1次元配列のまま | 行数が一致していること |
1次元配列を扱う際の挙動の違いは、初心者が最も混乱しやすいポイントの一つです。
「垂直(Vertical)=縦に積む」「水平(Horizontal)=横に並べる」というイメージを常に持っておきましょう。
注意点:形状(shape)の不一致によるエラー
NumPyの配列結合において最も頻繁に遭遇するトラブルが、ValueError: all the input array dimensions except for the concatenation axis must match exactlyというエラーです。
これは、結合しようとしている配列のサイズが、結合方向以外の軸で一致していないことを意味します。
# エラーが発生する例
arr1 = np.array([[1, 2], [3, 4]]) # 2x2
arr2 = np.array([[5, 6, 7]]) # 1x3
# 列数が異なるため、垂直結合できない
# np.vstack((arr1, arr2)) -> ValueError
このようなエラーを防ぐためには、結合前にarray.shapeを確認する習慣をつけることが大切です。
必要に応じて、reshape関数やnp.newaxisを使用して、次元を調整してから結合を行うようにしましょう。
汎用的な結合関数np.concatenateとの関係
実は、vstackやhstackは、より汎用的な関数であるnp.concatenateのラッパー(簡易版)です。
np.concatenateは、引数で指定するaxis(軸)の値によって、どの方向に結合するかを自由に決定できます。
np.vstack(tup)はnp.concatenate(tup, axis=0)とほぼ同等です。np.hstack(tup)はnp.concatenate(tup, axis=1)とほぼ同等です(ただし1次元配列は除く)。
日常的なコーディングでは、直感的に理解しやすいvstackやhstackを使用するのが一般的です。
しかし、3次元以上の多次元配列を扱う場合や、動的に結合方向を変えたい場合にはnp.concatenateを利用するのが適切です。
それぞれの特性を理解し、コードの可読性と柔軟性のバランスを考えて選択してください。
実践的な活用シーン:機械学習のデータ前処理
実際の開発現場では、vstackとhstackはどのように使われているのでしょうか。
具体的なシナリオをいくつか紹介します。
1. 複数のCSVファイルからのデータ統合
月ごとに分けられた売上データなどのCSVファイルを読み込み、一つの大きな行列にまとめる際にはnp.vstackが多用されます。
ループ内で個別に読み込んだ配列をリストに格納し、最後に一括で垂直結合することで、効率的にデータセットを構築できます。
2. 特徴量エンジニアリング
既存のデータセットに対して、新しく計算した統計量や特徴量を列として追加する場合にはnp.hstackが活躍します。
例えば、画像データから抽出した色ヒストグラムのベクトルと、テクスチャ特徴のベクトルを横に結合して、一つの入力ベクトルを作成するといったケースです。
3. ミニバッチの作成
ディープラーニングの学習において、個別のデータサンプルを束ねてミニバッチを作成する際にも、内部的にこれらの結合操作が行われています。
配列の形状を柔軟に操る能力は、アルゴリズムの実装力を高めるために不可欠です。
まとめ
NumPy配列の結合は、データ処理のあらゆる場面で登場する重要な操作です。
垂直方向に結合する np.vstack と、水平方向に結合する np.hstack の役割を正しく理解することで、コードの見通しが格段に良くなります。
特に1次元配列を扱う際の挙動の違いや、結合条件となる「形状の不一致」には十分に注意しましょう。
基本となるこれらの関数を使いこなせるようになれば、より高度なnp.concatenateやnp.stackへのステップアップもスムーズになります。
実際のプロジェクトでも、データの構造を常に意識しながら、最適な結合手法を選択することを心がけてください。
NumPyの強力な機能を活用して、効率的でミスのないデータ処理パイプラインを構築していきましょう。
