SciPy(サイパイ)は、NumPyの配列を使って最適化・数値積分・統計・信号処理・補間などを行うPythonの科学技術計算ライブラリです。この記事では、公式の読み方、NumPyとの役割の違い、pip install scipy の手順と失敗したときの対処、目的別のコード例を、2026年10月時点の最新版SciPy 1.18.1で実行した結果とあわせて説明します。
まとめ:SciPyの要点
- 読み方は「サイパイ」。SciPy公式のREADMEに
pronounced "Sigh Pie"と書かれています。 - NumPyは配列そのものと基本演算、SciPyはその配列に対する数値計算の手法(最小化・積分・検定・フィルタ・補間)を受け持ちます。SciPyを入れるとNumPyも依存として入ります。
- 最新版はSciPy 1.18.1(2026年8月21日)で、Python 3.12以上が必要です。Python 3.11で
pip install scipyを実行すると、エラーにならずに1.17.1が入ります。 - インストールで「Unknown compiler(s)」が出たら、wheel(ビルド済みの配布物)が無い環境でソースビルドに落ちています。コンパイラを入れる前に、Pythonの版と64ビット版かどうかを確かめます。
- バージョンは
scipy.__version__で確認します。scipy.odrは1.17.0で非推奨になり、1.19.0で削除される予定です。
SciPyの読み方は「サイパイ」
SciPyの読み方は「サイパイ」です。根拠は開発元の表記で、SciPyのGitHubリポジトリのREADMEの冒頭にSciPy (pronounced "Sigh Pie")とあります。カタカナで書くなら「サイパイ」です。
近いライブラリでは、scikit-learnは公式FAQに「sy-kit learn」(サイキット・ラーン)と書かれています。NumPyは公式サイトとリポジトリに読み方の記述がなく、「ナムパイ」「ナンパイ」の両方が使われています。NumPyの読み方の根拠はNumPyとは?読み方・インストール・基本的な使い方で詳しく扱っています。
SciPyでできること:サブパッケージ一覧
SciPyの機能は分野ごとのサブパッケージに分かれています。SciPy 1.18の公式APIリファレンスに載っているのは次の18個です。最適化・統計・積分など、本記事で扱う用途を中心に並べました。
| サブパッケージ | 用途 | 代表的な関数・クラス |
|---|---|---|
| scipy.optimize | 最小化・曲線あてはめ・線形計画・求根 | minimize, curve_fit, linprog, root_scalar |
| scipy.stats | 確率分布・統計検定・相関 | norm, ttest_ind, pearsonr |
| scipy.integrate | 数値積分・常微分方程式 | quad, solve_ivp |
| scipy.interpolate | 補間・スプライン | CubicSpline, make_interp_spline |
| scipy.linalg | 線形代数(NumPyより多い分解・行列関数) | solve, lu, expm, eigh |
| scipy.signal | フィルタ設計・スペクトル解析 | butter, sosfiltfilt, welch |
| scipy.fft | 高速フーリエ変換 | fft, rfft, rfftfreq |
| scipy.sparse | 疎行列 | csr_array, linalg.spsolve |
| scipy.spatial | 近傍探索・距離・凸包 | KDTree, distance.cdist |
| scipy.ndimage | 多次元画像処理 | gaussian_filter, label |
| scipy.cluster | 階層的クラスタリング・k-means | hierarchy.linkage, vq.kmeans2 |
| scipy.special | 特殊関数 | gamma, erf, comb |
| scipy.io | MATLAB・WAVなどの読み書き | loadmat, wavfile.read |
| scipy.constants | 物理定数・単位換算 | c, h, physical_constants |
| scipy.differentiate | 数値微分 | derivative, jacobian |
| scipy.datasets | サンプルデータの取得 | face, ascent |
| scipy.fftpack | 旧FFT(新規はscipy.fft) | fft |
| scipy.odr | 直交距離回帰(非推奨) | ODR |
このほかに、インストールしたSciPy 1.18.1には一覧に載っていない scipy.misc も残っています。importすると「scipy.misc is deprecated and will be removed in 2.0.0」という警告が出るので、新しいコードでは使いません。
SciPyとNumPyの違い:配列はNumPy、計算手法はSciPy
NumPyは多次元配列 ndarray と、その配列に対する四則演算・集計・基本的な線形代数を提供します。SciPyはNumPyの配列を入力に取り、その上で「最小値を探す」「積分する」「検定する」といった数値計算の手法を提供します。SciPyはNumPyに依存しますが、利用者のコードでNumPyを直接importする必要があるかは、処理によって異なります。SciPy 1.18.1はNumPy 2.0.0以上2.8未満を依存として要求するので(SciPy 1.18.1のpyproject.toml)、pip install scipy だけでNumPyも入ります。
違いが出るのは、NumPyに関数が無い処理です。SciPy 1.18.1とNumPy 2.5.4で確かめた結果を表にしました。
| やりたいこと | NumPy 2.5.4 | SciPy 1.18.1 |
|---|---|---|
| 連立一次方程式 | np.linalg.solve | scipy.linalg.solve |
| LU分解 | なし | scipy.linalg.lu |
| 行列指数関数 | なし | scipy.linalg.expm |
| 関数の最小化 | なし | scipy.optimize.minimize |
| 定積分 | なし(台形則のnp.trapezoidのみ) | scipy.integrate.quad |
| 補間 | np.interp(線形のみ) | CubicSpline など |
| 近傍点の探索 | なし | scipy.spatial.KDTree |
補間の差は数値で見るとわかりやすいです。y=x²の点(x=0〜4)から x=2.5 の値を求めると、np.interp は線形補間なので6.5、CubicSpline は6.25(真の値と一致)を返しました。線形補間で十分ならNumPyで対応でき、補間曲線の滑らかさが必要ならSciPyのCubicSplineが候補になります。
import numpy as np
from scipy.interpolate import CubicSpline
xs = np.array([0, 1, 2, 3, 4])
ys = xs ** 2
print(np.interp(2.5, xs, ys)) # 6.5
print(float(CubicSpline(xs, ys)(2.5))) # 6.25
データの読み込みや集計はpandas、学習モデルはscikit-learnと分担するのが一般的です。scikit-learnは内部でSciPyを使っており、Scikit-learnとは?読み方・できること・使い方で入れたときにもSciPyが一緒に入ります。
SciPyのインストール手順(pip・uv・conda)
pip install scipy の手順
pipで入れる場合は、仮想環境を作ってから入れます。SciPy公式のインストールガイドも、venvで環境を作って有効化したあとに python -m pip install scipy を実行する手順を示しています。pip を直接呼ぶより python -m pip の方が、どのPythonに入るかを取り違えません。
# macOS / Linux
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install scipy
python -c "import scipy; print(scipy.__version__)"
# Windows(PowerShell)
py -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install scipy
Python 3.12で実行すると、SciPy 1.18.1とNumPy 2.5.4が入りました。wheelの大きさは、macOS(Intel、macOS 14以降向け)で23.1MB、Linux x86_64で35.3MB、Windows x64で36.7MBです(PyPIの1.18.1の配布ファイル)。
uv・condaによるSciPyの導入
公式ガイドは、新しく始める人にはuvやpixiによるプロジェクト単位の管理を勧めています。uvなら uv init でプロジェクトを作り、uv add scipy で依存に加えます。
uv init myproject
cd myproject
uv add scipy
uv run python -c "import scipy; print(scipy.__version__)"
condaを使う場合、公式ガイドはMiniforgeを勧めており、環境を作ってから conda install scipy でconda-forgeから入れます。condaの環境にpipで同じパッケージを重ねると依存が壊れることがあるため、どちらか一方に寄せます。使い分けはpipとcondaの違いと使い分けにまとめています。
Pythonのバージョン別・導入可能なSciPy
SciPyは新しい版ほど古いPythonのサポートを外します。SciPy 1.18.0からはPython 3.12以上が必要です。pip install scipy は、そのPythonで動く範囲の最新版を選ぶため、Python 3.11ではエラーにならずに1.17.1が入ります。uvの依存解決で、Pythonの版ごとに入る版を確かめました(2026年10月27日時点)。
| Python | 入るSciPy | 入るNumPy |
|---|---|---|
| 3.12以上 | 1.18.1 | 2.5.4 |
| 3.11 | 1.17.1 | 2.4.6 |
| 3.10 | 1.15.3 | 2.2.6 |
| 3.9 | 1.13.1 | 2.0.2 |
チームで同じ結果を出したいなら、Pythonの版をそろえるのが先です。記事やサンプルの関数が見つからないときも、まず scipy.__version__ を見て、古い版が入っていないかを確かめます。
pip install scipy が失敗するときの対処
「No matching distribution found」:Pythonのバージョン要件不一致
版を指定して入れようとして、Pythonがその版の要件を満たしていないと、次のように弾かれます。Docker の python:3.11-slim で pip install scipy==1.18.1 を実行したときの出力(抜粋)です。
ERROR: Ignored the following versions that require a different python version: 1.18.0 Requires-Python >=3.12; ... 1.18.1 Requires-Python >=3.12; ...
ERROR: Could not find a version that satisfies the requirement scipy==1.18.1 (from versions: ... 1.17.0, 1.17.1)
ERROR: No matching distribution found for scipy==1.18.1
「Requires-Python >=3.12」が原因そのものです。Python 3.12以上の環境を作り直すか、そのPythonで入る1.17.1に指定を下げます。requirements.txtに他の環境で固定した版が書かれているときに起きやすいエラーです。
「Unknown compiler(s)」:ソースビルド時のコンパイラ不足
pipは、使っている環境向けのwheelがPyPIに無いと、ソース配布物(scipy-1.18.1.tar.gz)をダウンロードして手元でビルドしようとします。SciPyのビルドにはC・C++・Fortranのコンパイラと、BLAS/LAPACKのライブラリが必要です(SciPy公式のビルド手順)。コンパイラの無い環境では、メタデータの準備の段階で止まります。Docker の python:3.12-slim でソースビルドを強制したときの出力(抜粋)です。
Project name: scipy
Project version: 1.18.1
../meson.build:1:0: ERROR: Unknown compiler(s): [['cc'], ['gcc'], ['clang'], ['nvc'], ['pgcc'], ['icc'], ['icx']]
...
error: metadata-generation-failed
このエラーが出たら、コンパイラを入れる前に、なぜwheelが選ばれなかったかを確かめます。SciPy 1.18.1のwheelがあるのは、Python 3.12〜3.15の、Windows(x64・ARM64)、macOS(Intel・Apple Silicon)、Linux(x86_64・aarch64のglibc版とmusl版)です。次の環境はwheelの対象外です。
- Windowsの32ビット版Python(wheelはwin_amd64とwin_arm64だけ)
- glibcが2.27より古いLinux(Linux向けwheelのタグがmanylinux_2_27・manylinux_2_28)
- wheelが公開される前の新しいPython
対処は、64ビット版のPythonに入れ直す、wheelのあるPythonの版に合わせる、condaのconda-forgeから入れる、の順に試します。ソースビルドを選ぶのは、SciPyの開発に参加する場合か、wheelもconda-forgeのパッケージも無い環境に限ります。なお、SciPy 1.18.0ではFortranコンパイラなしでビルドする選択肢が試験的に入りましたが、リリースノートの位置づけは開発者の試験用途です(SciPy 1.18.0リリースノート)。
SciPyの使い方:目的別のコード例
以下はPython 3.12.13、SciPy 1.18.1、NumPy 2.5.4で実行したコードと出力です。乱数を使う例は np.random.default_rng(0) で固定しています。
最適化:minimize・curve_fit・linprog
minimize は関数の最小値を探します。methodを省略すると、制約(constraints)があればSLSQP、範囲(bounds)だけならL-BFGS-B、どちらも無ければBFGSが選ばれます(SciPy 1.18.0のminimizeのソース)。curve_fit はデータに式のパラメータを合わせ、linprog は線形計画問題を解きます。
import numpy as np
from scipy import optimize
# Rosenbrock関数の最小化(5変数)
r = optimize.minimize(optimize.rosen, x0=[1.3, 0.7, 0.8, 1.9, 1.2])
print(r.success, np.round(r.x, 4), r.nit) # True [1. 1. 1. 1. 1.] 25
# 指数減衰 a*exp(-b*t)+c をノイズ入りデータに当てはめる
rng = np.random.default_rng(0)
t = np.linspace(0, 4, 50)
y = 2.5 * np.exp(-1.3 * t) + 0.5 + rng.normal(0, 0.05, t.size)
p, cov = optimize.curve_fit(lambda t, a, b, c: a * np.exp(-b * t) + c, t, y, p0=[1, 1, 0])
print(np.round(p, 3)) # [2.504 1.384 0.534]
# 3x+2y を最大化(linprogは最小化なので符号を反転)
res = optimize.linprog(c=[-3, -2], A_ub=[[1, 1], [1, 3]], b_ub=[4, 6],
bounds=[(0, None), (0, None)])
print(res.x, res.fun) # [4. 0.] -12.0
print(res.message) # Optimization terminated successfully. (HiGHS Status 7: Optimal)
curve_fit は真の値(2.5、1.3、0.5)に近い2.504、1.384、0.534を返しました。linprog の既定のmethodは’highs’で、HiGHSの2つのソルバーから自動で選びます(linprogの公式リファレンス)。制約付き最適化の手法の選び方や、整数計画のmilpはscipy.optimizeの使い方|minimize・least_squares・milpで扱っています。
数値積分と微分方程式:quad・solve_ivp
quad は定積分を、solve_ivp は常微分方程式の初期値問題を解きます。solve_ivp は既定の許容誤差が粗い点に注意が要ります。
import numpy as np
from scipy import integrate
v, err = integrate.quad(lambda x: np.exp(-x ** 2), -np.inf, np.inf)
print(v, np.sqrt(np.pi)) # 1.7724538509055159 1.7724538509055159
# dy/dt = -0.5y, y(0)=2 の厳密解は 2*exp(-0.5t)
f = lambda t, y: -0.5 * y
exact = 2 * np.exp(-0.5 * np.array([2, 4, 10]))
s1 = integrate.solve_ivp(f, [0, 10], [2.0], t_eval=[2, 4, 10])
s2 = integrate.solve_ivp(f, [0, 10], [2.0], t_eval=[2, 4, 10], rtol=1e-8, atol=1e-10)
print(abs(s1.y[0] - exact).max()) # 0.000418...
print(abs(s2.y[0] - exact).max()) # 1.55e-09
既定のままだと厳密解との差が最大0.00042(t=2で0.73534に対し厳密解0.73576)でした。rtol=1e-8 と atol=1e-10 を指定すると差は1.6×10⁻⁹まで縮みます。必要な精度は方程式と用途によって異なります。描画用でも既定値で十分とは限らないため、許容誤差を小さくして結果の変化を確認します。
統計:t検定と確率分布
scipy.stats には100を超える確率分布と検定がまとまっています。2群の平均の差を調べる ttest_ind は、既定が等分散を仮定するStudentのt検定です。分散が等しいと言えないデータなら equal_var=False でWelchのt検定にします。
import numpy as np
from scipy import stats
rng = np.random.default_rng(0)
_ = rng.normal(0, 0.05, 50) # 上の例と同じ乱数列にそろえるための読み捨て
a = rng.normal(50, 5, 30)
b = rng.normal(53, 8, 30)
print(stats.ttest_ind(a, b)) # df=58.0, pvalue=0.3907
print(stats.ttest_ind(a, b, equal_var=False)) # df=50.79, pvalue=0.3912
print(stats.norm.ppf(0.975)) # 1.959963984540054
自由度がStudentでは58、Welchでは50.79になり、p値も変わります。今回の例では差は小さいですが、群の大きさと分散の両方が違うと結論が分かれることがあります。検定の選び方とp値の読み方は有意差検定とは?有意差・p値の意味と検定の種類で説明しています。
信号処理:ローパスフィルタによる高周波ノイズの低減
scipy.signal でフィルタを設計し、波形にかけます。5Hzの波に120Hzのノイズを足した信号に、30Hzのバターワース・ローパスフィルタ(4次)をかけました。
import numpy as np
from scipy import signal
fs = 1000 # サンプリング周波数 [Hz]
t = np.arange(0, 1, 1 / fs)
x = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 120 * t)
sos = signal.butter(4, 30, btype="low", fs=fs, output="sos")
y = signal.sosfiltfilt(sos, x) # 前後2回かけて位相のずれを打ち消す
amplitude = 2 * np.abs(np.fft.rfft(y)) / y.size
print(amplitude[5], amplitude[120]) # 約1.00015、約0.000712
FFTで振幅を測ると、5Hz成分は1.0から約1.00015へわずかに変わり、120Hz成分は0.5から約0.000712に下がりました。output="sos"(2次セクション形式)で設計しておくと、次数を上げても係数の丸め誤差で不安定になりにくくなります。
近傍探索:KDTree
多数の点から近い点を探すなら scipy.spatial.KDTree を使います。木によって探索候補を絞れますが、効率は次元数や点の分布に左右されます。KDTreeの公式リファレンスも、20次元でもすでに高次元で、総当たりより大幅に速くなるとは期待しないよう説明しています。
import numpy as np
from scipy.spatial import KDTree
rng = np.random.default_rng(1)
pts = rng.random((10000, 2)) # 1万点
tree = KDTree(pts)
dist, idx = tree.query([[0.5, 0.5]], k=3) # (0.5, 0.5) に近い3点
print(dist, idx) # [[0.00558033 0.00940872 0.01114484]] [[2186 1019 4630]]
SciPyで書いた計算を業務システムに組み込む段階では、入力データの受け渡しや実行の監視も含めた設計が要ります。そうした開発はフルスクラッチ開発として承っています。
バージョンの確認と非推奨モジュールの扱い
入っているSciPyの版は scipy.__version__ で、ビルドに使われたコンパイラやBLAS/LAPACKの種類は scipy.show_config() で確認できます。
import scipy
print(scipy.__version__) # 1.18.1
scipy.show_config() # コンパイラ、BLAS/LAPACK などのビルド情報
古い記事のコードが動かないときは、関数や引数の削除が原因のことがあります。SciPy 1.18.0では次の変更がありました(SciPy 1.18.0リリースノート)。
fmin_l_bfgs_bのiprint・disp、nnlsのatol、sqrtm・logm・signmのdispとsqrtmのblocksizeが削除された- FFTの内部実装がpocketfftから後継のducc0.fftに替わった
scipy.odr は1.17.0で非推奨になり、1.19.0で削除される予定です。scipy.odrの公式リファレンスは移行先としてPyPIの odrpack を案内しています。直交距離回帰を使っているコードは、1.19.0が出る前に移しておきます。
よくある質問
SciPyの読み方は?
「サイパイ」です。SciPy公式のREADMEにpronounced "Sigh Pie"と書かれています。
SciPyとNumPyの違いは?
NumPyは配列と基本演算、SciPyはその配列に対する最適化・積分・統計・信号処理・補間などの手法を提供します。SciPyはNumPyに依存しているので、SciPyを入れるとNumPyも一緒に入ります。
import scipy だけでサブパッケージは使えますか?
使えます。SciPy 1.9.0からサブパッケージは参照した時点で読み込まれるようになり、import scipy のあとに scipy.optimize.minimize_scalar(...) と書いても動きます。1.9.0のリリースノートは当初この書き方を対話的な利用向けとしていましたが、現在のSciPy公式APIリファレンスの「Guidelines for importing functions from SciPy」は、import scipy して scipy.optimize.curve_fit(...) と書く形を最初に示し、from scipy import optimize も同等の書き方として載せています。scipy.io は標準ライブラリの io と名前がぶつかるので、import scipy の形が勧められています。
Python 3.11で最新版のSciPyは使えますか?
使えません。SciPy 1.18.0以降はPython 3.12以上が必要で、Python 3.11で pip install scipy を実行すると1.17.1が入ります。1.18の機能が要るならPythonを3.12以上にします。
SciPyのライセンスは?商用利用できますか?
BSD 3-Clauseライセンスです。条件(著作権表示とライセンス文の保持など)を満たせば、改変の有無を問わずソースとバイナリの再配布・利用が認められており、商用のソフトウェアにも組み込めます。