NumPy集計・移動平均をC実装で高速化「Bottleneck」— nanmean が最大30倍速、move_mean は最大2500倍速
bash ファイル名.sh を実行してください(中身を一度確認してから実行すると安心です)。
(macOS / Linux 環境が必要) NumPy集計・移動平均をC実装で高速化「Bottleneck」— nanmean が最大30倍速、move_mean は最大2500倍速
ひとことでいうと
Bottleneck(ボトルネック)は、NumPy 配列の集計や移動平均などの計算を C 言語で作り直すことで大幅に速くした Python ライブラリです。np.nanmean や np.median といった NumPy の標準関数と同じ使い方ができるため、既存のコードをほとんど書き換えずに差し替えられます。小さな配列での nanmean は NumPy より最大 30 倍速く、移動平均(move_mean)は最大 2500 倍速いという計測結果も報告されています。データ分析や科学計算のコードを手軽に高速化したい、すべての Python ユーザーに向いているライブラリです。
こんな人におすすめ
1. データ分析・機械学習エンジニア
大規模な時系列データや数値の行列を扱い、nanmean や nanmedian などの集計処理が速度のボトルネック(処理全体の遅延を引き起こしている箇所)になっているときに、コードをほとんど変えずに速度を上げたい方に最適です。
2. Pandas をよく使う方
rolling() や shift() と同じ感覚で移動平均・移動標準偏差を計算したいが、さらに高いスループット(単位時間あたりの処理量)が必要な方。Bottleneck は Pandas の内部でも利用されており、直接使うことでオーバーヘッド(余分な処理コスト)をさらに減らせます。
3. 科学計算・数値シミュレーションの研究者 NaN(欠損値: 「値がない」を表す特別な数値)を含む float64 配列を頻繁に集計したり、スライディングウィンドウで配列を走査するシミュレーションコードを最適化したい方。欠損値が多いデータほど効果が大きくなります。
インストール・使い方
Bottleneck は PyPI(Python パッケージの配布サイト)にコンパイル済みのパッケージが公開されています。gcc などのコンパイラ(プログラムを機械語に変換するツール)がなくても、通常の環境ではそのままインストールできます。conda-forge 経由でも入手可能です。
Step 1: pip でインストール(推奨)
ターミナル(文字で命令を送る画面)を開き、以下のコマンドをコピー&ペーストして実行します。
pip install bottleneck
uv(高速パッケージマネージャー)を使う場合はこちらのコマンドを使います。
uv pip install bottleneck
コマンドを実行すると Bottleneck が自動でインストールされます。特別な設定は不要です。
Step 2: 基本的な使い方
Python ファイルや Jupyter Notebook(ブラウザ上で Python を書いて実行できるツール)に以下を書いて実行します。
import numpy as np
import bottleneck as bn
a = np.array([1, 2, np.nan, 4, 5])
# NaN を無視した平均(np.nanmean の高速版)
print(bn.nanmean(a)) # 3.0
# 移動平均(window=2、最低1要素あれば計算)
print(bn.move_mean(a, window=2, min_count=1))
# array([ 1. , 1.5, 2. , 4. , 4.5])
bn.nanmean(a) は np.nanmean(a) とまったく同じ結果を返します。np. を bn. に変えるだけで高速化できるのが最大の特徴です。
Step 3: ベンチマークで速度を確認する
import bottleneck as bn
bn.bench()
bn.bench() を実行すると、NumPy との処理速度比較が自動的に表示されます。表示される倍率(「29.8x faster」など)が大きいほど Bottleneck が速いことを示します。自分の環境での実際の効果をここで確認しておくと、最適化の優先順位を決めやすくなります。
ブラウザで試す(デモ)
主要な NaN-aware 集計関数(NaN を無視して集計する関数)と移動平均の動作、NumPy との速度比較をブラウザ上で試せるデモが用意されています。インストールなしでそのまま体験できるため、まず動きを確認したい場合に便利です。
動かしてみた
PyPI からバイナリホイール(コンパイル済みのプラットフォーム別パッケージ)をインストールした場合、コンパイラは一切不要です。インストール後に bn.test() を実行すると、pytest(Python のテストツール)が起動して 190 件のテストが完走することが確認されています。
bn.bench() の出力(README 掲載)では、小さな配列 (100,) に対する nanmean が NumPy 比 29.8 倍速、move_mean が 2575.8 倍速 という結果が示されています。特に移動窓演算(配列を一定の幅でずらしながら集計する処理)での高速化が際立っています。
なお、大きな行列(例: 1000×1000)の axis=0 演算(列方向への集計)では、配列のサイズや計算する軸の向きによって効果に差が出ることがあります。小さな配列・NaN の多い配列・移動窓演算の場面で特に高速化の恩恵を受けやすい設計です。
試す前に知っておくとよい環境の目安は以下のとおりです。
| 項目 | 内容 |
|---|---|
| OS | Linux / macOS / Windows |
| Python | 3.9 以上 |
| NumPy | 1.16.0 以上 |
| コンパイラ | gcc / clang / MinGW / MSVC(ソースからビルドする場合のみ) |
| テストツール | pytest |
実践のコツ — はじめの一歩
まず次のコードをそのまま Jupyter Notebook やスクリプトにコピー&ペーストして実行してみてください。欠損値(NaN)を約 20% 含む配列を作り、nanmean の速度を NumPy と Bottleneck で比べるコードです。
import numpy as np
import bottleneck as bn
import time
# 欠損値を含む配列を生成
rng = np.random.default_rng(42)
a = rng.random(1000)
a[rng.random(1000) < 0.2] = np.nan # 約 20% を NaN に
# NumPy vs Bottleneck の速度比較
for label, func in [("NumPy", np.nanmean), ("Bottleneck", bn.nanmean)]:
t0 = time.perf_counter()
for _ in range(10000):
func(a)
print(f"{label} nanmean: {(time.perf_counter() - t0)*1000:.2f} ms")
# 移動平均
result = bn.move_mean(a, window=10, min_count=1)
print("移動平均(最初の5要素):", result[:5])
実行すると処理時間の差が数字で確認できます。速度差を目で見ると、どの場面で Bottleneck を使うべきかイメージが掴みやすくなります。
さらに効果を高めるポイントを以下にまとめます。
- まず
bn.bench()を実行して倍率を確認する: 自分の環境での速度倍率を把握してから最適化対象を選ぶと、効果の大きい箇所に集中できます。 - 小さな配列・NaN が多いデータから試す: Bottleneck が最も効果を発揮するのは小〜中規模の配列や欠損値が多いデータです。まずこのケースから差し替えを試しましょう。
import bottleneck as bnの一行だけ追加する: 既存コードへの組み込みは、import 文(ライブラリを読み込む宣言)と関数名のプレフィックス変更だけです。大規模なリファクタリング(コードの整理)は不要です。move_meanのmin_countを活用する: 時系列の先頭など窓が埋まりきらない部分でも計算を継続したい場合はmin_count=1を指定すると NaN を返さずに動作します。bn.test()でインストール確認をしておく: セットアップ後に一度実行しておくと、環境固有の問題を早期に発見できます。
活用例
- IoT・センサーデータの前処理: デバイスから取得した欠損値含みの時系列データに対して、
bn.move_meanやbn.move_stdでスライディングウィンドウ集計を高速に行い、リアルタイムに近い処理を実現します。 - 金融データ分析: 株価・為替レートの移動平均線やボリンジャーバンド(価格の変動幅を示す指標)の計算に
bn.move_mean・bn.move_stdを使い、pandas のrolling()よりも低オーバーヘッドで高頻度データを処理できます。 - 機械学習の特徴量エンジニアリング: 百万行規模のデータセットでローリング特徴量(移動窓ベースの入力データ)を大量に生成する際に、Bottleneck を使うことでパイプライン全体の処理時間を大幅に短縮できます。
- 気象・環境データの集計: 観測機器から得た大量の欠損値を含む気温・降雨量データの移動平均や分散を効率よく計算し、異常値の検出や可視化に活用できます。
- 医療・バイオインフォマティクス: ゲノムデータや生体信号など、欠損値が多い大規模配列の統計集計を高速化して、実験サイクルを短縮できます。
- 教育・学習: NumPy の
nanmeanなどと比較しながら Bottleneck を使うことで、C 言語による高速化の仕組みやパフォーマンスチューニングの考え方を実際の数値で体験的に学べます。
用語とポイント解説
NaN(ナン)
かんたんに言うと「値がない」を表す特別な数値です。センサーが計測できなかった瞬間や、スプレッドシートの空欄が読み込まれたときなどに現れます。Python・NumPy では np.nan と書き表します。集計関数に NaN が混じると通常は結果が NaN になるため、専用の関数で処理する必要があります。
NaN-aware 関数
かんたんに言うと、NaN を「なかったこと」にして集計してくれる関数です。nanmean(NaN 無視の平均)・nansum(NaN 無視の合計)・nanmedian(NaN 無視の中央値)などが代表例です。Bottleneck では NumPy の同名関数より小配列で数十倍高速になることがあります。
移動窓(ムービングウィンドウ)
かんたんに言うと、配列の中を一定の「窓」の幅でずらしながら集計していく操作です。例えば window=10 なら直近 10 個の値で平均を計算し、1 要素ずつ窓をずらして繰り返します。時系列分析の基本操作で、Bottleneck では C で実装されているため極めて高速です。
move_mean / move_std / move_median
かんたんに言うと、移動平均・移動標準偏差・移動中央値をそれぞれ計算する Bottleneck の関数です。min_count パラメーターで「窓内に最低何個の有効値があれば計算するか」を指定でき、時系列の先頭部分でも NaN を返さずに動作させられます。
ドロップイン置換
かんたんに言うと、元のコードをほぼ書き換えずに別の実装に差し替えられる設計のことです。np.nanmean(...) を bn.nanmean(...) に変えるだけで動作するため、リファクタリング(コードの整理)コストを最小化できます。
バイナリホイール(.whl ファイル) かんたんに言うと、コンパイル(機械語への変換)済みのパッケージファイルです。PyPI から取得することでコンパイラなしでインストールでき、環境構築の手間が大幅に減ります。Windows・macOS・Linux それぞれ向けに用意されています。
C 拡張(C エクステンション) かんたんに言うと、Python から呼び出せる C 言語で書かれた処理のことです。Python は人間が読みやすい反面、純粋な Python コードよりも C の処理は数十〜数千倍速くなることがあります。Bottleneck はこの仕組みを使って NumPy の関数を再実装しています。
ベンチマーク
かんたんに言うと、処理速度を測定・比較するテストのことです。Bottleneck では bn.bench() を実行するだけで NumPy との速度比較が自動的に表示されます。どの関数でどれくらい速いかを一覧で確認できます。
pydata エコシステム かんたんに言うと、NumPy・pandas・SciPy・Matplotlib など、Python でのデータ分析・科学計算を支えるライブラリ群の総称です。Bottleneck はこの pydata プロジェクトの一部として開発・メンテナンスされており、pandas の内部でも利用されるほど実績があります。
axis パラメーター
かんたんに言うと、多次元配列のどの方向(行方向・列方向など)に計算するかを指定する引数です。axis=0 なら列ごとに集計、axis=1 なら行ごとに集計します。配列のサイズや axis の指定によって Bottleneck の高速化効果の大きさが変わるため、実際に bn.bench() で確認するのがおすすめです。
ぜひ時系列センサーデータの移動平均処理や、機械学習パイプラインの特徴量エンジニアリングなどに活用してみてはいかがでしょうか。