Pythonを用いたデータ分析や数値計算において、特定の数値で埋め尽くされた配列を準備するシーンは非常に多く存在します。
例えば、初期値として全ての要素を「-1」に設定したり、特定のフラグ値で配列を初期化したりする場合です。
このようなタスクを直感的かつ効率的に実行するための関数が、NumPyライブラリのnp.fullです。
np.fullは、指定した形状(shape)と値(fill_value)に基づいて、すべての要素が同じ値を持つ配列を生成します。本記事では、この関数の基本的な使い方から、実務でハマりやすいデータ型(dtype)の注意点、さらには他の配列生成関数とのパフォーマンスの違いまで、プロの視点で詳しく解説します。
NumPyのnp.fullとは:定数配列を生成する基本
NumPyには配列を生成するための便利な関数が多数用意されていますが、その中でも「任意の定数で埋められた配列」を生成することに特化しているのがnp.fullです。
以前のPythonコードでは、np.onesで作成した配列に数値を掛け算する手法も使われていましたが、np.fullを使用する方がコードの意図が明確になり、可読性が向上します。
また、内部的な処理としても、特定の値を直接メモリに書き込むため効率的です。
基本的な構文と引数の解説
まずは、np.fullの基本的な構文を確認しましょう。
import numpy as np
# 基本構文
# np.full(shape, fill_value, dtype=None, order='C', *, like=None)
主要な引数の役割は以下の通りです。
| 引数名 | 概要 |
|---|---|
shape | 配列の形状を指定します。整数(1次元)または整数のタプル(多次元)で指定します。 |
fill_value | 配列を埋めるための定数値を指定します。 |
dtype | 配列のデータ型を指定します。省略した場合は fill_value から推論されます。 |
order | メモリ上の配置順序を指定します(’C’は行優先、’F’は列優先)。通常はデフォルトのままで問題ありません。 |
特に重要なのは、shapeとfill_valueの2点です。これらを正しく組み合わせることで、目的に応じた多次元配列を瞬時に作成できます。
np.fullの具体的な使い方
ここからは、コード例を交えて具体的な使い道を見ていきましょう。
1次元配列から多次元配列、そして既存の配列の形状を模倣する方法まで紹介します。
1次元配列と多次元配列の生成
もっともシンプルな例として、5つの要素をすべて「7」で埋めた1次元配列を作成します。
import numpy as np
# 要素数5、値が7の1次元配列
arr_1d = np.full(5, 7)
print(arr_1d)
[7 7 7 7 7]
次に、2行3列の行列(2次元配列)を「0.5」で埋める例です。
import numpy as np
# 2行3列、値が0.5の2次元配列
arr_2d = np.full((2, 3), 0.5)
print(arr_2d)
[[0.5 0.5 0.5]
[0.5 0.5 0.5]]
このように、shapeにタプルを渡すだけで、任意の次元の定数配列を簡単に作成できるのがnp.fullの強みです。
既存の配列をベースにするnp.full_like
「すでにある配列と同じ形状、同じデータ型で、別の値で埋めたい」という場合には、np.full_likeが便利です。
import numpy as np
base_array = np.array([[1, 2], [3, 4]])
# base_arrayと同じ形状で、すべての値を-1にする
new_array = np.full_like(base_array, -1)
print(new_array)
[[-1 -1]
[-1 -1]]
np.full_likeを使うことで、元の配列のshapeやdtypeをわざわざ取得して再指定する手間が省け、コードがスッキリします。
dtype(データ型)の指定と注意点
np.fullを使用する際に最も注意すべきなのが、「データ型の推論」です。
NumPyは、提供された fill_value から最適なデータ型を自動的に決定しようとしますが、これが予期せぬ挙動を招くことがあります。
自動推論の挙動と明示的な指定の重要性
例えば、整数を渡せば int 型になり、浮動小数点数を渡せば float 型になります。
import numpy as np
a = np.full(3, 10) # int64 (環境依存)
b = np.full(3, 10.0) # float64
print(f"a dtype: {a.dtype}")
print(f"b dtype: {b.dtype}")
a dtype: int64
b dtype: float64
ここで問題になるのは、後から配列の要素を書き換える場合です。
もし整数型で初期化された配列に、後から小数を入れると、小数点以下が切り捨てられてしまいます。
import numpy as np
arr = np.full(3, 1) # int型で生成
arr[0] = 1.9 # floatを代入しようとする
print(arr)
[1 1 1]
上記の結果のように、1.9を代入したつもりが「1」になってしまいます。
これを防ぐためには、生成時に明示的に dtype を指定することが推奨されます。
# 明示的にfloat型を指定
arr = np.full(3, 1, dtype=np.float64)
arr[0] = 1.9
print(arr)
[1.9 1. 1. ]
浮動小数点数(NaN)で埋める際の注意
欠損値を表す np.nan で配列を埋めたい場合、np.nan 自体が浮動小数点数型であるため、自動的に float 型の配列が作成されます。
しかし、整数型の配列に NaN を入れることはできないため、混合して扱う可能性がある場合は最初から dtype=float を意識しましょう。
他の配列生成関数との比較
NumPyには他にも配列を生成する関数があります。
np.full と何が違うのか、どのように使い分けるべきかを整理します。
zeros、ones、emptyとの違いと使い分け
- np.zeros: すべての要素を「0」で初期化します。0で埋めることが確定しているなら、
np.full(shape, 0)よりも高速で直感的です。 - np.ones: すべての要素を「1」で初期化します。
- np.empty: メモリ領域を確保するだけで、中身を初期化しません。そのため非常に高速ですが、中身には「以前使われていたメモリのゴミデータ」が入っています。生成直後にすべての要素を上書きする場合にのみ推奨されます。
以下の表に使い分けをまとめました。
| 関数 | 適した用途 | 速度 |
|---|---|---|
np.zeros | 0で初期化する場合 | 高速 |
np.ones | 1で初期化する場合 | 高速 |
np.full | 0, 1以外の特定の数値で初期化する場合 | 標準 |
np.empty | 即座に全要素を別データで埋める場合 | 最速 |
実務において、例えば「全ての要素を100で埋める」場合に np.ones(shape) * 100 と書く人がいますが、これは「1で埋める処理」と「100を掛ける処理」の2段階が発生するため、np.full(shape, 100) と書く方がパフォーマンスとコードの明快さの両面で優れています。
応用編:実践的な活用シーン
np.full は単なる初期化以外にも、多くの場面で応用されています。
初期値としての利用とマスク処理
アルゴリズムの実装において、最短距離を求めるダイクストラ法などのグラフ理論では、各ノードへの距離を最初に「無限大(infinity)」で初期化することがよくあります。
このような場合、np.inf を使って次のように作成します。
import numpy as np
# 無限大で初期化されたコスト行列
costs = np.full((5, 5), np.inf)
print(costs)
[[inf inf inf inf inf]
[inf inf inf inf inf]
[inf inf inf inf inf]
[inf inf inf inf inf]
[inf inf inf inf inf]]
また、画像処理や機械学習のデータ前処理において、特定の値を背景色やパディング値として利用する際にも np.full は重宝されます。
実行速度とメモリ効率
大量のデータを扱う際、np.full の実行速度が気になるかもしれません。
NumPyはC言語で実装されているため、Pythonのループでリストを作成するよりも圧倒的に高速です。
ただし、非常に巨大な配列を生成する場合、メモリ消費量に注意が必要です。
dtype=np.int64(8バイト)で 1,000,000 要素の配列を作ると、それだけで約8MBのメモリを消費します。
用途に応じて int32 や float32 を選択することで、メモリ使用量を半分に抑えることが可能です。
まとめ
NumPyの np.full は、任意の定数で埋められた配列を効率的に作成するための強力なツールです。
本記事のポイントを振り返ります。
- np.fullは、指定した形状と値で配列を即座に生成する。
np.ones() * valueよりも可読性が高く、効率的である。- dtypeを明示的に指定しないと、意図しない型変換(切り捨て)が発生する恐れがある。
- 既存の配列の形状をコピーしたい場合は
np.full_likeが便利である。 - 0や1で埋める場合は
np.zerosやnp.onesを選ぶのが定石。
データサイエンスや科学計算の現場では、正確な数値管理が求められます。
配列生成の第一歩として np.full を正しく使いこなし、堅牢でクリーンなPythonコードを目指しましょう。
