Numba(ナンバ)は、Pythonで書いた数値計算の関数を実行時にLLVMで機械語へコンパイルし、ループ中心の処理を大きく速くできるオープンソースのJITコンパイラです。関数に@njitを1行付けるだけで使え、コードはPythonのまま残せます。この記事では、2026年9月30日リリースの最新版0.68.0に合わせて、インストール(Intel Macの注意点を含む)、@njitの使い方、Python 3.14で実際に測ったNumPy・並列化・fastmathとの速度差、GPU(CUDA)向けのnumba-cudaへの移行、エラーの読み方までを整理します。
まとめ:Numbaの要点
- NumbaはPythonの関数をLLVMで機械語にするJITコンパイラ。読み方は「ナンバ」。
- 導入は
pip install numbaかconda install numba。最新0.68.0はPython 3.10〜3.15、NumPy 1.22〜1.26と2.0〜2.5に対応する。 - Intel Mac(x86_64)向けのwheelは0.63.0からPyPIに無い。pipはソースビルドになり、LLVMなどのビルド環境が無いと失敗するので、conda-forgeから入れるのが手堅い。
- 使い方は関数に
@njitを付けるだけ。1,000万要素の二乗和の実測では、Pythonのforループ(換算値)より約107倍速くなった。 - 同じ二乗和では、NumPyの
np.dot(4.60ミリ秒)が@njit(15.69ミリ秒)より速かった。NumPyの関数で書ける処理は、Numba化の前に両方を測って決める。 - Numba内蔵のGPU(CUDA)ターゲットは0.61で非推奨。移行先のnumba-cudaも保守モードに入り、NVIDIAは新規開発先のNumba-CUDA-MLIRを推奨している。
- コンパイル時のTypingErrorは、型の混在とpandasのDataFrameの受け渡しで起きやすい。
Numbaとは:PythonをLLVMで高速化するJITコンパイラ
Numbaは、Anaconda社が開発を主導してきたオープンソースのJIT(Just-In-Time)コンパイラです。読み方は「ナンバ」。Pythonのインタプリタは命令を1つずつ解釈しながら実行するため、単純な四則演算を大量に繰り返すループでは速度が出ません。Numbaは対象の関数を初めて呼び出したときに機械語へコンパイルし、2回目以降はコンパイル済みのネイティブコードを実行して、この解釈のコストを取り除きます。ソースコードと開発状況はGitHubのnumba/numbaリポジトリで公開されています。
NumbaがPythonを高速化する仕組み
Numbaは呼び出し時の引数の型から関数内の変数の型を推論し、その型に特化した中間表現を作ってLLVMでCPUの機械語に変換します。0.68.0が使うllvmlite 0.50系はLLVM 22系で、実際にllvmlite.binding.llvm_version_infoを確認すると(22, 1, 0)でした。Cythonのように別ファイルへ書き直してビルドする手順は不要で、関数はPythonのまま残ります。型ごとにコンパイル結果を持つので、同じ関数にfloat64配列とint64配列を渡すと、それぞれ1回ずつコンパイルが走ります。
Numbaが効く処理・効かない処理
効果が大きいのは、Pythonのforループでスカラー演算を大量に回す処理と、前の要素の結果に次の計算が依存するためNumPyの配列演算に置き換えにくい逐次計算です。逆に、I/O待ちが主体の処理は計算を速くしても全体が縮みにくく、NumPyの関数がすでに最適化している処理は伸びしろが小さくなります。文字列や辞書を扱う処理はnopythonモードで使える機能に制約があります。どこまで速くなるかは下の実測章、使わない判断は後半の章で示します。
Numbaのインストール手順(pip / conda)
NumbaはPyPIとconda(Anacondaのnumbaチャネルとconda-forge)の両方で配布されています。venvやuvで管理している環境ならpip、Anaconda・Miniforgeの環境ならcondaを使います。両者を同じ環境で混ぜると依存が壊れやすいので、管理方法はpipとcondaの違いと使い分け|混ぜると壊れる理由とAnaconda・Miniforgeの選び方を参考に1つに決めてください。
pipとcondaのインストールコマンド
pipでは次の1行で、依存するllvmliteとNumPyも入ります。
pip install numba
Anaconda・Miniforgeの環境ではcondaを使います。Intel Macではconda-forgeを指定してください(理由は次の次の節)。
conda install numba
# Intel Mac(osx-64)の場合
conda install -c conda-forge numba
入ったかどうかは、Pythonからバージョンを出すか、Numbaに付属するnumba -sで確認します。numba -sはCPUの種類と命令セット(AVX2など)、OS・Python・LLVMなどのバージョンをまとめて出力するので、速くならない・GPUが見えないといった相談をするときにもそのまま貼れます。
python -c "import numba; print(numba.__version__)"
numba -s
Numba 0.68.0の対応バージョン
公式のVersion support informationでは、0.68.0の対応範囲は次のとおりです。Python 3.15への対応は0.68.0のリリースノートで追加され、NumPy 2.5への対応は1つ前の0.67.0で入りました。
| 項目 | 0.68.0の対応範囲 |
|---|---|
| リリース日 | 2026年9月30日 |
| Python | 3.10以上3.16未満 |
| NumPy | 1.22以上1.27未満/2.0以上2.6未満 |
| llvmlite | 0.50.x |
| LLVM | 22.x |
Python 3.9以前とNumPy 2.6以降は対象外です。フリースレッド版(GILなし)のPython 3.14tは0.63.0で実験的に対応が始まり、0.65.0から3.14t向けのwheelが配布されています。Numbaのリリースは1〜2か月おきなので、導入前にPyPIのnumbaのページで最新版を確認してください。
Intel MacでのNumbaのpipインストール失敗と対処
Numbaは0.63.0(2025年12月)でIntel Mac(osx-64)をTier 2のサポートに下げ、この版からPyPIにmacOS x86_64向けのwheelを置いていません。PyPIで確認すると、x86_64のmacOS向けwheelがあるのは0.62.x系までです。そのためIntel Macでpip install numbaを実行すると、0.68.0のソース配布物からllvmliteとNumbaをビルドしようとします。ソースビルドには公式の手順どおりLLVMなどを用意する必要があり、用意していない環境では失敗します。LLVMを入れていないIntel Mac(Core i9)でuvを使い、Python 3.13と3.14の仮想環境に入れた結果は次の3通りでした。
| コマンド | Python | 結果 |
|---|---|---|
pip install numba |
3.13 | llvmlite 0.50.0のビルドで失敗 |
| wheelのみ許可 | 3.13 | 0.62.1が入る(NumPy 2.3.5) |
| wheelのみ許可 | 3.14 | 入れられる版がなく失敗 |
エラーの末尾にはllvmlite (v0.50.0) was included because numba (v0.68.0) depends on llvmliteと出ます。wheelだけを許可すると古い0.62.1に黙って下がり、Python 3.14ではどの版も入りません。conda-forgeには0.68.0のosx-64版があるので、Intel Macで最新版を使うならMiniforgeなどでconda-forgeから入れるのが手堅い方法です。既存のpip環境を残したい場合は、Numbaを使う処理だけ別のconda環境に分けるか、LLVMを用意してソースからビルドします。
Numbaの基本的な使い方:@njitによる関数の高速化
Numbaの中心は関数デコレータです。高速化したい関数に@njitを付けると、初回呼び出し時にその引数の型でコンパイルされます。次は1,000万要素の配列の二乗和を求める例です。
import numpy as np
from numba import njit
@njit
def sum_sq(a):
s = 0.0
for i in range(a.shape[0]):
s += a[i] * a[i]
return s
x = np.random.default_rng(0).random(10_000_000)
print(sum_sq(x)) # 初回だけコンパイルが走る
@jitと@njitの違い(nopythonモード)
@njitは@jit(nopython=True)の省略形で、Pythonのオブジェクトを一切使わないnopythonモードで関数全体をコンパイルします。0.59.0のリリースノートでnopythonの既定値がTrueになり、コンパイルできない関数を遅いobject modeで黙って動かすフォールバックも廃止されました。0.59.0以降は@jitと@njitの動きは同じで、どちらを書いてもコンパイルできなければエラーになります。2020年前後の解説記事にある「@jitだと遅いことがある」はこのフォールバックの話で、今の版には当てはまりません。新しく書くコードは意図が読み取れる@njitをおすすめします。
初回コンパイルの時間と計測の注意
初回呼び出しにはコンパイル時間が含まれます。下の実測環境では、上のsum_sqの初回呼び出しが384ミリ秒で2回目以降の最小値は15.69ミリ秒、parallel=True版は初回685ミリ秒で2回目以降の最小値は5.54ミリ秒でした。速度を比べるときは一度呼んでコンパイルを済ませてから、複数回測って最小値か中央値を取ります。採否は呼び出し回数ではなく、コンパイル込みの総時間で判断します。二乗和なら初回384ミリ秒でも、Pythonのループ(換算約1,678ミリ秒)より短く済みます。
Numba 0.68.0の速度を実測:NumPy・並列化・fastmathとの比較
「Numbaで何倍速くなるか」は処理の形でまったく変わります。2種類の処理で、Pythonのループ・NumPy・Numbaの各オプションを測りました。数値は繰り返し測った最小値で、回数はPythonのループが3回、NumPyとNumbaが5回(fastmathの比較は7回)です。
- 環境:Docker(Linux x86_64・4 CPU、ホストはCore i9-9880H)、Python 3.14.8、Numba 0.68.0、NumPy 2.5.4、llvmlite 0.50.0
- Pythonのforループは時間がかかるため100万要素で測り、10倍して1,000万要素に換算。表の「Pythonループ比」はこの換算値に対する倍率
- NumPyのBLASはOpenBLAS 0.3.34(4スレッド・pthreads)。Numbaの並列版は4スレッド(スレッド層workqueue)。いずれも
threadpoolctlとnumba.get_num_threads()で確認 - 結果の検算:閾値リセット累積和は100万要素でPython版と
@njit版をnp.allcloseで照合、二乗和は@njit版とnp.dotの相対差が10-9未満、fastmath版と並列版は@njit版との相対差が約1.2〜1.5×10-13
| 処理(1,000万要素) | 方法 | 時間 | Pythonループ比 |
|---|---|---|---|
| 二乗和 | Pythonのforループ | 約1,678 ms | 1倍 |
| 二乗和 | NumPy np.dot(x, x) |
4.60 ms | 約365倍 |
| 二乗和 | @njit |
15.69 ms | 約107倍 |
| 二乗和 | @njit(fastmath=True) |
6.82 ms | 約246倍 |
| 二乗和 | @njit(parallel=True)+prange |
5.54 ms | 約303倍 |
| 閾値でリセットする累積和 | Pythonのforループ | 約2,878 ms | 1倍 |
| 閾値でリセットする累積和 | @njit |
78.67 ms | 約37倍 |
二乗和で見るNumPyとNumbaの速度差
二乗和はNumPyならnp.dot(x, x)の1行で、この環境ではBLAS(OpenBLAS)が計算します。素の@njitはPythonループの約107倍まで速くなりましたが、それでもnp.dotの3倍以上遅い結果でした。NumbaはLLVMのループのベクトル化(SIMD)を既定で使いますが、浮動小数点の合計のようなリダクションは、足す順序を入れ替えると結果がわずかに変わるため、既定ではベクトル化されません。fastmath=Trueで順序の入れ替えを許すと6.82ミリ秒まで縮み、np.dotとの差は約1.5倍になりました。この二乗和のようにNumPyにぴったりの関数がある処理は、Numba化する前にNumPy版と測り比べ、速いほうを残してください。SIMDとコンパイラのベクトル化の関係はSIMDとは?AVX2・NEONの仕組みと自動ベクトル化・組み込み関数の書き方で詳しく扱っています。
閾値リセット累積和で見るNumbaの効果
「累積和が閾値3.0を超えたら0に戻す」処理は、各要素が直前の結果に依存するため、NumPyのnp.cumsumでは書けません。前の要素の結果を持ち回るループは@njitでそのまま機械語になるので、表のとおりPythonのループ(換算値)との差がはっきり出ます。こうした逐次処理、条件分岐の多いシミュレーション、自作のアルゴリズムがNumbaの本来の守備範囲です。
@njit
def reset_cumsum(a, th):
out = np.empty_like(a)
s = 0.0
for i in range(a.shape[0]):
s += a[i]
if s > th:
s = 0.0
out[i] = s
return out
parallel=Trueによる並列化の効果
parallel=Trueを付けてループをprangeに変えると、4スレッドで5.54ミリ秒と、素の@njitの約2.8倍になりました。合計を求めるs += ...はNumbaが並列リダクションとして扱います。一方で初回のコンパイルは685ミリ秒と、素の@njit(384ミリ秒)より長くかかりました。付けるかどうかは、コンパイル込みの総時間と2回目以降の時間を、付けない版と実際のデータで比べて決めます。
Numbaの高速化オプション:fastmath・cache・vectorize
デコレータに引数を加えると、さらに速度やコンパイル時間を調整できます。fastmathと並列化の考え方は公式のPerformance Tipsにも実測例付きで載っています。
fastmath=Trueの速度と精度
fastmath=TrueはIEEE 754の厳密な規則を緩め、演算の順序の入れ替えなどを許可します。上の二乗和では15.69ミリ秒が6.82ミリ秒になり、結果の相対差は約1.2×10-13でした。NaNや無限大が入りうるデータでは、NaNが無いことを前提にした最適化で結果が変わることがあるため、入力を検証してから使います。なお、Performance TipsにあるIntel SVMLによる三角関数などの高速化は、0.65.0のリリースノートで「0.62.0から使えない状態が続いている」と明記されています。古い記事のSVMLの数値は今の版では再現しません。
@njit(fastmath=True)
def sum_sq_fast(a):
s = 0.0
for i in range(a.shape[0]):
s += a[i] * a[i]
return s
cache=Trueによるコンパイル結果の再利用
cache=Trueを付けると、コンパイル結果を__pycache__に保存し、次のプロセスでは再コンパイルを省きます。条件分岐を含む小さな関数をスクリプトとして2回起動したところ、初回呼び出しは1回目の491ミリ秒から2回目は254ミリ秒に縮みました。ゼロにはならず、この環境ではNumPyとNumbaのimportにも毎回約0.4秒かかりました。今回は関数を.pyファイルに保存して確認しました。次のように保存して2回起動し、2回目の初回呼び出しが短くなるかで確かめられます。
# cachetest.py(python cachetest.py を2回実行して比べる)
import time
import numpy as np
from numba import njit
@njit(cache=True)
def score(a):
s = 0.0
for i in range(a.shape[0]):
if a[i] > 0.5:
s += a[i] ** 2
else:
s -= a[i]
return s
a = np.random.rand(1000)
t0 = time.perf_counter()
score(a)
print(f"first call {1000 * (time.perf_counter() - t0):.1f} ms")
@vectorizeによるufunc作成
要素ごとに同じ計算を適用する関数は、@vectorizeでNumPyのユニバーサル関数(ufunc)にできます。作ったufuncはNumPy配列をそのまま受け取り、ブロードキャストにも対応します。型シグネチャを文字列で渡すと、定義した時点でコンパイルされます。
from numba import vectorize
@vectorize(["float64(float64, float64)"])
def clipped_diff(a, b):
d = a - b
return d if d > 0 else 0.0
NumbaとNumPyの違いと使い分け
NumbaとNumPyはどちらも数値計算を速くしますが、仕組みが違います。NumPyはC実装の関数で配列全体を一括処理し、NumbaはPythonで書いた関数そのものを機械語にします。NumPyの基礎はNumPyとは?読み方・インストール・基本的な使い方をPythonで解説で確認できます。
| 観点 | NumPy | Numba |
|---|---|---|
| 速くする方法 | C実装の配列演算 | 関数をJITコンパイル |
| 得意な処理 | 1関数で書ける配列演算 | 逐次計算・条件分岐の多いループ |
| 書き方 | ループを配列演算に置き換える | Pythonのループのまま書ける |
| 初回の待ち時間 | なし | 数百ミリ秒のコンパイル |
判断の起点は「NumPyの関数1つか2つで素直に書けるか」です。書けるならまずNumPy版を作り、np.whereや一時配列を何段も重ねないと書けない処理は、Numbaでループに戻した版と測り比べます。実際にはNumbaの関数がNumPy配列を受け取ってループで処理する組み合わせが一般的で、両者は競合しません。
NumbaでのGPU(CUDA)利用:numba-cudaとNumba-CUDA-MLIR
Numbaは@cuda.jitでNVIDIA GPU上のカーネルをPythonで書けます。ただし、GPU向けの実装は置き場所が2回変わっています。公式の非推奨一覧によると、Numbaに内蔵のCUDAターゲットは0.61で非推奨になり、開発はNVIDIAのnumba-cudaパッケージへ移りました。そのnumba-cudaも、ドキュメント冒頭の告知で保守モードに入ったことが明記されています。今後はCUDA 13の期間中、セキュリティ問題と重大なバグの修正だけを行い、新機能の開発はNumba-CUDA-MLIRで進めるとしており、NVIDIAはできるだけ早い移行を推奨しています。0.68.0にも内蔵版のnumba/cudaは残っていますが、新しくGPUのコードを書くならNumba-CUDA-MLIRを第一候補にしてください。
numba-cudaとNumba-CUDA-MLIRの導入
Numba-CUDA-MLIRのREADMEによると、導入はpipで、CUDAの版を追加指定で選びます。要件はPython 3.10以上(0.5.4のPyPIの記載。READMEには3.11以上と残っている)、Compute Capability 7.0以上のNVIDIA GPU、CUDA 12.xならr525以上・CUDA 13.xならr580以上のドライバーです。pipで入るのはライブラリとCUDAの実行時コンポーネントまでなので、GPUドライバーは別に用意します。PyPIの版は2026年10月時点で0.5.4です。
pip install "numba-cuda-mlir[cu13]" # CUDA 12なら [cu12]
移行は、多くのコードでimportの1行を書き換えるだけで済むとされています。コード生成にLLVM IRではなくMLIRを使うため、拡張APIを使っているコードは修正が必要です。
# 書き換え前(Numba内蔵版・numba-cuda)
from numba import cuda
# 書き換え後(Numba-CUDA-MLIR)
from numba_cuda_mlir import cuda
@cuda.jit
def add_kernel(x, y, out):
i = cuda.grid(1)
if i < x.size:
out[i] = x[i] + y[i]
既存のコードを当面numba-cudaで動かす場合は、numba-cudaの導入文書どおりpip install "numba-cuda[cu12]"かpip install "numba-cuda[cu13]"で入れます。numba-cudaを入れるとfrom numba import cudaの実体がnumba-cuda側に切り替わります(numba 0.68.0とnumba-cuda 0.30.4で確認)。追加指定なしで入れたCUDAランタイムの無い環境では、import時にFailure finding "libcudart.so.13 or libcudart.so.12"で止まりました。
GPUで速くならない典型パターン
GPUのメモリはCPUと別なので、cuda.to_device()でデータを送り、copy_to_host()で結果を戻します。データが小さい処理ではこの転送時間が計算時間を上回り、GPUにしても遅くなります。まずCPU側の@njitと並列化で足りるかを測り、それでも足りない規模になってからGPUを検討してください。NumPyのコードをそのままGPUで動かしたいだけなら、カーネルを自分で書くNumbaより、NumPy互換APIを持つCuPyのほうが手間は少なく済みます。
Numbaのエラー・速くならないときの対処
この章では、nopythonモードで型を決められないときに出るTypingErrorと、速くならないときの確認手順を扱います。エラーは0.68.0で実際に出したものです。
TypingError:Cannot unifyの原因と型の統一
1つの変数に整数と文字列を代入すると、TypingErrorになります。
@njit
def bad(n):
x = 1
if n > 0:
x = "text"
return x
bad(3)
# TypingError: Failed in nopython mode pipeline (step: nopython frontend)
# Cannot unify Literal[int](1) and Literal[str](text) for 'x.2', defined at ...
Cannot unify A and Bは「この変数がAにもBにもなりうるので1つの型に決められない」という意味です。エラーには行番号が出るので、その変数が関数内で常に同じ型になるように直します。要素の型がばらばらのリストを渡したときも同じ系統のエラーになります。numba.typed.Listも要素の型が1種類である必要があるので、まず要素の型を揃え、そのうえでNumPy配列かnumba.typed.Listに入れて渡します。
TypingError:Cannot determine Numba typeとDataFrameの受け渡し
pandasのDataFrameや任意のPythonオブジェクトをそのまま渡すと、引数の型を決められずに止まります。
import pandas as pd
from numba import njit
@njit
def usedf(df):
return df["a"].sum()
usedf(pd.DataFrame({"a": [1, 2]}))
# TypingError: ... non-precise type pyobject
# - argument 0: Cannot determine Numba type of <class 'pandas.DataFrame'>
Numbaが直接扱えるのは数値・NumPy配列・タプルなどです。直すには、関数の引数をNumPy配列にし、列の選択(df["a"])は関数の外へ出します。to_numpy()の結果の型は列のデータ型で決まり、文字列などが入ったobject型の列はNumbaに渡せないので、先にdtypeが数値型であることを確認します。
@njit
def col_sum(a):
return a.sum()
col_sum(df["a"].to_numpy()) # int64の配列なら動く(結果は3)
前処理はpandasのまま行い、重い数値計算だけを@njitの関数に切り出すのが定石です。
速くならないときの確認手順
- 初回呼び出し(コンパイル込み)を測っていないか。2回目以降で比べる。
- NumPyの1関数で済む処理をNumba化していないか。二乗和のように
np.dotのほうが速い処理がある。 - ループの中でリストや辞書、Pythonオブジェクトを作っていないか。
- 浮動小数点の合計ならfastmath、重いループなら
parallel=Trueの余地がないか。 numba -sでCPUの命令セット(AVX2など)が認識されているか。
Numbaを使うべきでない場面と代替手段の選び方
Numbaは数値ループには強い一方で、合わない場面もはっきりしています。次のどれかに当てはまるなら、Numbaは使わないと判断してよいでしょう。
- 処理時間の大半がI/Oや通信の待ち時間。計算を速くしても全体は縮まない。
- 文字列・辞書・クラスが中心の処理。nopythonモードの対応が限られ、書き換えのほうが高くつく。
- NumPy版と測り比べて速くならない処理。二乗和の実測のように、NumPyの関数のほうが速いことがある。
- コンパイルとimportの追加時間(この環境では数百ミリ秒と約0.4秒)が、削れる計算時間を上回る用途。起動の速さが重要な小さなCLIが典型。
- Intel Macの共有環境をpipだけで管理していて、conda環境の追加もLLVMを用意したソースビルドもできない。0.63.0以降はPyPIにwheelが無い。
代替手段の目安は次のとおりです。クラスや文字列を含むロジック全体をコンパイルしたい、C/C++の資産とつなぎたい場合は、型を宣言してCへ変換するCythonとは?使い方・インストールと型宣言の効果を実測(Cython 3.3対応)が向きます。対応するPythonのコードをAOTでネイティブコードにするCodonや、Pythonに似た文法の別言語Mojoとの速度の比較は、Cython・Codon・Mojo実測比較|Pythonコードは何倍速くなるかにまとめています。CPython本体のJITについてはPython 3.14のJITコンパイラとは?有効化の手順と実測、フリースレッド版と新機能で扱っており、こちらはコードを書き換えずに使えますが、数値ループでNumbaほどの伸びは期待できません。数値計算の高速化を含む業務システムを設計から作る場合は、フルスクラッチ開発の段階でNumbaを使う範囲と使わない範囲を決めておくと、後からの書き換えが少なく済みます。
よくある質問
Numbaの読み方は?
「ナンバ」と読みます。NumPyの配列を扱えるPython向けのJITコンパイラという位置づけで、公式サイトのタイトルは「Numba: A High Performance Python Compiler」です。
@jitと@njitはどちらを使えばいいですか?
どちらでも同じ動きです。0.59.0で@jitの既定がnopythonモードになり、@njitと同じになりました。意図が読み取りやすい@njitをおすすめします。
NumbaはPython 3.15やNumPy 2.5に対応していますか?
対応しています。0.68.0(2026年9月30日)でPython 3.15に、0.67.0でNumPy 2.5に対応しました。NumPy 2.6以降は0.68.0の対応範囲外です。
pandasのDataFrameをNumbaで扱えますか?
DataFrameを@njitの関数に直接渡すことはできず、Cannot determine Numba typeのエラーになります。数値型の列をdf["col"].to_numpy()でNumPy配列にしてから渡してください。object型になる列は渡せません。
numba-scipyでSciPyの関数を高速化できますか?
おすすめしません。PyPIのnumba-scipyの最終版は2024年4月の0.4.0で、依存はscipy<=1.11.0に固定され、GitHubのREADMEではプロジェクトが保留(on hold)とされています。SciPyの関数はPython側で呼び、Numbaには数値ループだけを任せてください。