SciPy Cheatsheet
Special Functions
Use this SciPy reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Core Import
from scipy import special import numpy as np # Common direct imports from scipy.special import ( # Gamma & related gamma, gammaln, gammasgn, loggamma, rgamma, multigammaln, gammainccinv, gammainc, gammaincc, gammaincinv, psi, digamma, polygamma, beta, betaln, betainc, betaincinv, # Error functions erf, erfc, erfinv, erfcinv, erfi, # Bessel functions jv, yv, iv, kv, jn, yn, j0, j1, y0, y1, i0, i1, k0, k1, jvp, yvp, ivp, kvp, jn_zeros, jnp_zeros, # Airy functions airy, airye, ai_zeros, bi_zeros, # Orthogonal polynomials eval_legendre, eval_chebyt, eval_chebyu, eval_hermite, eval_laguerre, eval_genlaguerre, # Hypergeometric hyp1f1, hyp2f1, hyp0f1, # Elliptic integrals ellipk, ellipe, ellipkm1, ellipj, # Combinatorics comb, perm, factorial, factorial2, # Information theory entr, rel_entr, xlogy, xlog1py, # Statistical ndtr, ndtri, chdtr, stdtr, # Misc expit, logit, log1p, expm1, sinc, sici, shichi, zeta, zetac, lambertw, # Spherical harmonics sph_harm_y, )
Beta Function
from scipy.special import beta, betaln, betainc, betaincinv beta(2, 3) # B(2,3) = Γ(2)Γ(3)/Γ(5) = 1/12 betaln(2, 3) # log(B(2,3)), more stable # Regularized incomplete beta I_x(a,b) betainc(2, 3, 0.5) # (a, b, x) betaincinv(2, 3, 0.6875) # (a, b, p) — inverse
Error Functions
from scipy.special import erf, erfc, erfinv, erfcinv, erfi, erfcx # erf(x) = (2/sqrt(pi)) * int_0^x exp(-t^2) dt erf(1.0) # ≈ 0.8427 erfc(1.0) # 1 - erf(x) ≈ 0.1573 (more accurate for large x) erfinv(0.8) # inverse erf erfcinv(0.2) # inverse erfc # Imaginary error function erf(ix)/i erfi(1.0) # Scaled complementary: erfcx(x) = exp(x^2) * erfc(x) (no overflow) erfcx(10.0) # avoids overflow where erfc underflows
Bessel Functions
Cylindrical Bessel (General Order)
from scipy.special import jv, yv, iv, kv, jvp, yvp, ivp, kvp # J_v(z) — Bessel of the first kind; args are (v, z): order, then argument jv(0, 1.0) jv(1.5, np.linspace(0, 10, 100)) # Y_v(z) — Bessel of the second kind (Neumann) yv(0, 2.0) # I_v(z) — modified Bessel of the first kind iv(0, 1.0) # K_v(z) — modified Bessel of the second kind kv(0, 1.0) # Derivatives jvp(0, 1.0, n=1) # (v, z, n): d/dz J_0(z) at z=1 ivp(0, 1.0, n=2) # second derivative of I_0
Integer-Order Fast Implementations
from scipy.special import j0, j1, y0, y1, i0, i1, i0e, i1e, k0, k1, k0e, k1e j0(x), j1(x) # J_0, J_1 (fast C implementations) y0(x), y1(x) # Y_0, Y_1 i0(x), i1(x) # I_0, I_1 i0e(x), i1e(x) # exp(-abs(x)) * I_0(x): exponentially scaled (avoids overflow) k0(x), k1(x) # K_0, K_1 k0e(x), k1e(x) # exp(x) * K_0(x): exponentially scaled
Zeros of Bessel Functions
from scipy.special import jn_zeros, jnp_zeros, yn_zeros, ynp_zeros # First nt zeros of J_n(x) jn_zeros(0, 5) # [2.4048, 5.5201, 8.6537, 11.7915, 14.9309] jn_zeros(1, 3) # First nt zeros of J_n'(x) jnp_zeros(0, 5)
Spherical Bessel Functions
from scipy.special import spherical_jn, spherical_yn, spherical_in, spherical_kn spherical_jn(0, 1.0) spherical_jn(1, 1.0, derivative=True) # derivative spherical_yn(0, 1.0)
Airy Functions
from scipy.special import airy, airye, ai_zeros, bi_zeros # Ai(z), Ai'(z), Bi(z), Bi'(z) Ai, Aip, Bi, Bip = airy(1.0) # Exponentially scaled (avoids overflow for large z) Ai_e, Aip_e, Bi_e, Bip_e = airye(10.0) # Zeros a, ap, ai_ap, aip_a = ai_zeros(5) # zeros of Ai, zeros of Ai', values Ai(a'), values Ai'(a)
Orthogonal Polynomials
from scipy.special import ( eval_legendre, eval_chebyt, eval_chebyu, eval_hermite, eval_hermitenorm, eval_laguerre, eval_genlaguerre, eval_jacobi ) # Legendre P_n(x), x in [-1, 1] — args are (n, x) eval_legendre(3, 0.5) # Chebyshev T_n(x) (first kind), U_n(x) (second kind) eval_chebyt(4, 0.5) eval_chebyu(4, 0.5) # Hermite H_n(x) (physicists') and He_n(x) (probabilists') eval_hermite(3, 1.0) eval_hermitenorm(3, 1.0) # Laguerre L_n(x), generalized L_n^alpha(x): (n, alpha, x) eval_laguerre(3, 1.0) eval_genlaguerre(3, 0.5, 1.0) # Jacobi P_n^(alpha,beta)(x): (n, alpha, beta, x) eval_jacobi(3, 0.5, 0.5, 0.5)
Polynomial Objects (Weights, Roots, etc.)
from scipy.special import roots_legendre, roots_chebyt, roots_hermite, roots_laguerre # Gauss-Legendre quadrature nodes and weights x, w = roots_legendre(10) # on [-1, 1] # Gauss-Chebyshev x, w = roots_chebyt(10) # Gauss-Hermite (physicists') x, w = roots_hermite(10) # Gauss-Laguerre x, w = roots_laguerre(10) # on [0, ∞)
Hypergeometric Functions
from scipy.special import hyp1f1, hyp2f1, hyp0f1 # Confluent hypergeometric: M(a, b, z) = 1F1(a; b; z) — args (a, b, z) hyp1f1(1, 2, 1.0) # Gauss hypergeometric: 2F1(a, b; c; z), |z| < 1 — args (a, b, c, z) hyp2f1(0.5, 0.5, 1.0, 0.5) # 0F1(; b; z) — Bessel-related — args (b, z) hyp0f1(1.0, 1.0)
Elliptic Integrals
from scipy.special import ellipk, ellipe, ellipkm1, ellipj # Complete elliptic integral of the first kind K(m), second kind E(m) # Note: argument is m = k^2, not k K = ellipk(0.5) # K(k^2 = 0.5) E = ellipe(0.5) # E(k^2 = 0.5) # K(1-m) for near m=1 (avoids cancellation) K1m = ellipkm1(0.001) # = ellipk(1 - 0.001) but more accurate # Jacobi elliptic functions sn(u|m), cn(u|m), dn(u|m), ph — args (u, m) sn, cn, dn, ph = ellipj(1.0, 0.5)
Combinatorics
from scipy.special import comb, perm, factorial, factorial2 # Binomial coefficient C(N, k) comb(10, 3) # 120.0 (float) comb(10, 3, exact=True) # 120 (int, slower for large N) comb(10, 3, repetition=True) # with repetition = C(N+k-1, k) # Permutations P(N, k) perm(10, 3) # 720.0 perm(10, 3, exact=True) # 720 (int) # Factorial factorial(10) # 3628800.0 factorial(10, exact=True) # 3628800 (int) factorial2(7) # 7!! = 7*5*3*1 = 105
Logit, Expit (Sigmoid)
from scipy.special import expit, logit, log_expit # Sigmoid: expit(x) = 1 / (1 + exp(-x)) expit(0.0) # 0.5 expit(np.array([-3, 0, 3])) # Inverse sigmoid: logit(p) = log(p/(1-p)) logit(0.5) # 0.0 logit(0.9) # ≈ 2.197 # Numerically stable log(sigmoid): log_expit(x) = log(1/(1+exp(-x))) log_expit(-100.0) # no underflow
Information-Theoretic Functions
from scipy.special import entr, rel_entr, xlogy, xlog1py, kl_div # entr(x) = -x*log(x) (0 if x=0, -inf if x<0) entr(0.5) # ≈ 0.347 # rel_entr(x, y) = x*log(x/y) (0 if x=0, inf if y=0 and x!=0) rel_entr(0.3, 0.7) # xlogy(x, y) = x*log(y) (0 if x=0, even if y=0) xlogy(0, 0) # 0 (not NaN) xlogy(2, 3) # 2*log(3) # kl_div(x, y) = x*log(x/y) - x + y kl_div(0.3, 0.7) # KL divergence between two distributions p = np.array([0.2, 0.5, 0.3]) q = np.array([0.1, 0.6, 0.3]) kl = np.sum(rel_entr(p, q)) # KL(P || Q)
Sinc, Si, Ci, Shi, Chi
from scipy.special import sinc, sici, shichi # Normalized sinc: sin(pi*x) / (pi*x) sinc(1.5) # Sine and cosine integrals: Si(x), Ci(x) Si, Ci = sici(np.pi) # Hyperbolic sine and cosine integrals: Shi(x), Chi(x) Shi, Chi = shichi(1.0)
Spherical Harmonics
from scipy.special import sph_harm_y # SciPy 1.15+ # Y_n^m(theta, phi): args are (n, m, theta, phi) # n = degree (l), m = order # theta = POLAR angle (colatitude) in [0, pi] # phi = AZIMUTHAL angle in [0, 2*pi] Y = sph_harm_y(2, 1, np.pi/4, np.pi/3) # Returns complex value # Grid of values theta = np.linspace(0, np.pi, 50) phi = np.linspace(0, 2*np.pi, 100) T, P = np.meshgrid(theta, phi) Y_grid = sph_harm_y(3, 2, T, P)
Legacy
sph_harm(deprecated 1.15, removed 1.17): the oldsph_harm(m, n, theta, phi)put the order first and — infamously — usedthetaas the AZIMUTHAL angle andphias the polar angle, the reverse of the standard physics convention.sph_harm_yfixes both: degree first, and theta/phi carry their conventional meanings.
Zeta Functions
from scipy.special import zeta, zetac # Riemann zeta: one-argument zeta(x) = sum_{k=1}^∞ 1/k^x zeta(2) # ≈ pi^2/6 = 1.6449... # Hurwitz zeta: zeta(x, q) = sum_{k=0}^∞ 1/(k+q)^x zeta(2, 1) # q=1 reduces to the Riemann zeta # zetac(x) = zeta(x) - 1 (accurate for large x, where zeta ≈ 1) zetac(2)
Lambert W Function
from scipy.special import lambertw # Principal branch W_0: W(z) * exp(W(z)) = z lambertw(1.0) # ≈ 0.5671 (Omega constant) lambertw(0) # 0 lambertw(-1/np.e) # -1 (branch point) # Secondary real branch W_{-1} for z in [-1/e, 0) lambertw(-0.1, k=-1) # k=-1 branch # Complex input lambertw(-1.0 + 0j)
Numerical Stability Notes
| Function | Stable Alternative | When to Use |
|---|---|---|
gamma(x) | gammaln(x) | When Γ(x) would overflow/underflow |
erfc(x) | erfcx(x) * exp(-x**2) | Large x (erfc underflows) |
i0(x) | i0e(x) * exp(-abs(x)) | Large x |
log(1 + x) | log1p(x) | Small x near 0 |
exp(x) - 1 | expm1(x) | Small x near 0 |
p * log(q) | xlogy(p, q) | p may be 0 |
p * log(1 + q) | xlog1py(p, q) | q near 0 |
from scipy.special import log1p, expm1 # Precision near x=0 np.log(1 + 1e-15) # 0.0 (catastrophic cancellation) log1p(1e-15) # 9.99e-16 (correct) np.exp(1e-15) - 1 # 0.0 (precision lost) expm1(1e-15) # 1e-15 (correct)
Common Gotchas
Bessel argument convention:
jv(v, z)is order then argument. Easy to swap.j0(x)andj1(x)(nov) are always faster for fixed integer orders.
Elliptic integral argument: SciPy uses
m = k²(the modulus squared), NOTk. Many textbooks usek.ellipk(0.5)computes K(k) where k² = 0.5, i.e. k ≈ 0.707.
Most
scipy.specialfunctions are NumPy ufuncs — they accept positional arguments only.jv(v=0, z=1.0)raisesTypeError; writejv(0, 1.0).
Spherical harmonics angle convention: use
sph_harm_y(n, m, theta, phi)(SciPy 1.15+) — theta is the polar angle (colatitude, [0, π]), phi the azimuth ([0, 2π]). The removed legacysph_harmhad these two SWAPPED (theta = azimuth), a long-standing trap when porting old code.
combreturns float by default even for integer inputs. Useexact=Truefor exact integer arithmetic (required for large combinatoric calculations).
gammaoverflows forz > 171.6. Usegammaln+ work in log space, thennp.expat the end.