Pythonを用いたデータ分析や機械学習、科学技術計算において、NumPyは欠かすことのできない基盤ライブラリです。
多次元配列であるndarrayを効率的に扱うことが、プログラム全体のパフォーマンスを左右すると言っても過言ではありません。
その中でも、特定の値で配列を初期化する操作は、計算の土台を作るための極めて重要なステップです。
本記事では、NumPyで最も頻繁に利用される初期化関数であるnp.zerosとnp.onesの使い方を軸に、引数の詳細な指定方法や実務的な使い分けについて詳しく解説します。
2026年現在の最新のNumPy(バージョン2.x系列)の仕様を前提とした、最適な実装手法を確認していきましょう。
NumPyにおける配列初期化の重要性
プログラム内で数値計算を行う際、あらかじめ決まった形状の配列を確保しておくことは、メモリ管理と計算効率の両面で大きなメリットがあります。
Pythonの標準リストとは異なり、NumPyの配列はメモリ上の連続した領域に配置されるため、あらかじめサイズを確定させてから値を代入していく手法が一般的です。
配列を初期化する関数はいくつか存在しますが、その代表格がnp.zerosとnp.onesです。
これらは、単に0や1で埋めるだけの関数に見えますが、データ型(dtype)の指定やメモリレイアウト(order)の選択により、その後の計算スピードに大きな影響を与えることがあります。
np.zerosによる0埋め配列の生成
np.zerosは、指定した形状(shape)ですべての要素が0の配列を生成する関数です。
画像処理における黒塗りのキャンバス作成や、ニューラルネットワークの重みの勾配を蓄積するためのバッファ、あるいは累積加算の初期状態として非常によく使われます。
np.zerosの基本的な使い方
まずは、最もシンプルな1次元配列と2次元配列の生成方法を見てみましょう。
import numpy as np
# 5つの要素を持つ1次元配列を生成
zeros_1d = np.zeros(5)
print("1次元配列:")
print(zeros_1d)
# 2行3列の2次元配列を生成
# 形状はタプル (rows, cols) で指定する点に注意
zeros_2d = np.zeros((2, 3))
print("\n2次元配列:")
print(zeros_2d)
1次元配列:
[0. 0. 0. 0. 0.]
2次元配列:
[[0. 0. 0.]
[0. 0. 0.]]
ここで注目すべきは、デフォルトでは浮動小数点数(float64)として生成される点です。
出力結果に0.とドットが付いているのは、それが整数ではなく浮動小数点数であることを示しています。
引数 shape の指定ルール
np.zerosの第一引数であるshapeには、整数または整数のタプルを渡します。
多次元配列を作成する場合、np.zeros(2, 3)のように個別の引数として渡すとエラーになります。
必ず np.zeros((2, 3)) のようにタプルで一括して渡すのがNumPyのルールです。
これは、後述する他の初期化関数でも共通の仕様となっています。
np.onesによる1埋め配列の生成
np.onesは、すべての要素を1で初期化する関数です。
恒等的な処理や、特定の値を掛ける前のベース配列、あるいはマスク処理における「すべて有効」なフラグとして利用されます。
np.onesの基本的な使い方
np.onesも、使い方はnp.zerosと全く同じです。
import numpy as np
# 4つの要素を持つ1次元配列を生成
ones_1d = np.ones(4)
print("1次元配列:")
print(ones_1d)
# 3行2列の2次元配列を生成
ones_2d = np.ones((3, 2))
print("\n2次元配列:")
print(ones_2d)
1次元配列:
[1. 1. 1. 1.]
2次元配列:
[[1. 1.]
[1. 1.]
[1. 1.]]
特定の値で初期化したい場合(応用)
「すべて5で初期化したい」という場合、np.onesで作成した配列にスカラー値を掛ける手法があります。
# すべての要素を5.0で初期化
fives = np.ones((2, 2)) * 5
print(fives)
[[5. 5.]
[5. 5.]]
ただし、現在では特定の任意の値で埋めたい場合にはnp.fullという関数を使う方が直感的で推奨されます。
しかし、np.onesとの使い分けとして、「1をベースにした比率」などを扱う際には、依然としてこの乗算スタイルも散見されます。
データ型(dtype)の明示的な指定
NumPyの配列操作で最もエラーやパフォーマンス低下を招きやすいのが、データ型(dtype)の不一致です。
デフォルトではfloat64が選択されますが、メモリを節約したい場合や整数値が必要な場合は、明示的に指定する必要があります。
dtype引数の活用例
# 整数型(int32)で0埋め配列を作成
zeros_int = np.zeros((2, 2), dtype=np.int32)
print("整数型のzeros:")
print(zeros_int)
# 8ビット符号なし整数(uint8)で1埋め配列を作成(画像データの最小単位など)
ones_uint8 = np.ones((2, 2), dtype=np.uint8)
print("\nuint8型のones:")
print(ones_uint8)
整数型のzeros:
[[0 0]
[0 0]]
uint8型のones:
[[1 1]
[1 1]]
実行結果を見ると、数値の後ろにドット(.)が付いていないことがわかります。
これは整数型として正しく生成されている証拠です。
2026年現在の環境においても、大規模なデータを扱う際にはfloat64からfloat32への変更、あるいは適切な整数型へのキャストは、メモリ消費を半分に抑えるための必須テクニックです。
既存の配列と同じ形状で作る:_like関数の活用
実務では、「既にある配列と同じサイズ、同じデータ型の空配列(または0埋め配列)が欲しい」という場面が多々あります。
その際に便利なのがnp.zeros_likeとnp.ones_likeです。
np.zeros_likeのメリット
これらを使うと、元の配列のshapeやdtypeをわざわざ調べて引数に渡す手間が省けます。
base_array = np.array([[1.5, 2.3], [4.1, 5.9]], dtype=np.float32)
# base_arrayと同じ形状・型で0埋め配列を作成
new_zeros = np.zeros_like(base_array)
print("元の配列の型:", base_array.dtype)
print("新しい配列の型:", new_zeros.dtype)
print("新しい配列の内容:\n", new_zeros)
元の配列の型: float32
新しい配列の型: float32
新しい配列の内容:
[[0. 0.]
[0. 0.]]
このように、元の配列の属性をそのまま引き継げるため、コードの可読性が高まり、バグの混入を防ぐことができます。
メモリレイアウト(order)の指定
NumPyの配列には、メモリ上にデータをどのように並べるかという「オーダー」の設定があります。
| オーダー | 指定値 | 説明 |
|---|---|---|
| C-order | order='C' | 行(Row)を優先してメモリに配置。Python/Cのデフォルト。 |
| Fortran-order | order='F' | 列(Column)を優先してメモリに配置。Fortran系ライブラリとの連携用。 |
通常はデフォルトの'C'で問題ありませんが、特定の行列演算や、深層学習フレームワークとの低レイヤーでの連携において、列優先の配置が求められることがあります。
初期化時に指定可能です。
# 列優先(Fortran形式)で初期化
f_order_array = np.zeros((10, 10), order='F')
np.zeros / np.ones と np.empty の違い
初期化において、np.emptyという関数もよく登場します。
これは「値を初期化せずにメモリ領域だけを確保する」関数です。
- np.zeros / np.ones: メモリ確保後、すべての要素に0や1を書き込む(安全だが、わずかに時間がかかる)。
- np.empty: メモリ確保のみを行い、中身は以前そのメモリ領域を使っていたデータの残骸(ゴミデータ)が入る(高速だが、すぐに値を代入しないとバグの原因になる)。
2026年時点の最新ハードウェアと最適化されたNumPyにおいても、巨大な配列(数GB単位)を扱う場合は np.empty の方が高速ですが、一般的なデータ処理であれば安全性の高いnp.zerosを選択するのがベストプラクティスです。
実践的な使い分けとヒント
ここでは、どのようなシーンでどの関数を使うべきかの指針をまとめます。
1. カウンタや累積用の変数として使う
何かを数え上げたり、合計値を保持したりするための配列が必要な場合は、迷わずnp.zerosを使用します。
np.emptyで作成してしまうと、初期値が0でないために計算結果が狂うリスクがあります。
2. マスク配列を作成する
特定の条件を満たす要素のみを抽出したい場合、まずnp.onesで「すべて有効(1またはTrue)」な配列を作成し、不要な部分を0に書き換えるというアプローチが取られます。
3. ニューラルネットワークの重み初期化
近年、重みの初期化にはHeの初期化やXavierの初期化などの乱数ベースの手法が用いられますが、バイアス(Bias)の項については、伝統的にnp.zerosで初期化されるのが一般的です。
4. 2026年における最新の注意点:NumPy 2.xでのdtypeの扱い
NumPy 2.0以降、データ型のプロモーションルール(型昇格ルール)が厳格化・整理されました。
例えば、異なる精度を持つ配列同士の演算において、意図しない型変換が発生しにくくなっています。
そのため、np.zeros(..., dtype=...)で初期化する際も、後続の演算対象となる配列の型と一致させておくことが、不必要なメモリアロケーションや警告を防ぐコツとなります。
まとめ
本記事では、NumPyにおける配列初期化の基本であるnp.zerosとnp.onesについて、その詳細な使い方と引数の設定、そして実務上の使い分けを解説しました。
重要なポイントを振り返ります。
- np.zerosは0で、np.onesは1で配列を初期化する。
- 形状(shape)を指定する際は、多次元なら必ずタプルで渡す。
- デフォルトのデータ型は
float64であるため、整数が必要な場合はdtype=np.int32などを指定する。 - 既存の配列と同じ形状にしたい場合は、
np.zeros_likeなどの「_like」系関数が非常に便利。 - 速度を極限まで追求し、直後にすべての値を上書きする場合は
np.emptyを検討するが、基本的にはnp.zerosが安全。
適切な初期化手法を選択することは、コードの堅牢性を高めるだけでなく、大規模データ処理におけるメモリ効率の向上にも直結します。
2026年のエンジニアリングシーンにおいても、これらの基本関数を正確に使いこなすことが、高品質なPythonプログラムを構築するための第一歩となるでしょう。
ぜひ今回の内容を参考に、日々の開発に役立ててください。
