| name | scipy |
| description | Comprehensive guide for SciPy - the fundamental library for scientific and technical computing in Python. Use for integration, optimization, interpolation, linear algebra, signal processing, statistics, ODEs, Fourier transforms, and advanced scientific algorithms. Built on NumPy and essential for research and engineering. |
| version | 1.12 |
| license | BSD-3-Clause |
SciPy - Scientific Computing
Advanced scientific computing library built on NumPy, providing algorithms for optimization, integration, interpolation, and more.
When to Use
- Integrating functions (numerical integration, ODEs)
- Optimizing functions (minimization, root finding, curve fitting)
- Interpolating data (1D, 2D, splines)
- Advanced linear algebra (sparse matrices, decompositions)
- Signal processing (filtering, Fourier transforms, wavelets)
- Statistical analysis (distributions, hypothesis tests)
- Image processing (filters, morphology, measurements)
- Spatial algorithms (distance matrices, clustering, Voronoi)
- Special mathematical functions (Bessel, gamma, error functions)
- Solving differential equations (ODEs, PDEs)
Reference Documentation
Official docs: https://docs.scipy.org/
Search patterns: scipy.integrate.quad, scipy.optimize.minimize, scipy.interpolate, scipy.stats, scipy.signal
Core Principles
Use SciPy For
| Task | Module | Example |
|---|
| Integration | integrate | quad(f, 0, 1) |
| Optimization | optimize | minimize(f, x0) |
| Interpolation | interpolate | interp1d(x, y) |
| Linear algebra | linalg | linalg.solve(A, b) |
| Signal processing | signal | signal.butter(4, 0.5) |
| Statistics | stats | stats.norm.pdf(x) |
| ODEs | integrate | solve_ivp(f, t_span, y0) |
| FFT | fft | fft.fft(signal) |
Do NOT Use For
- Basic array operations (use NumPy)
- Machine learning (use scikit-learn)
- Deep learning (use PyTorch, TensorFlow)
- Symbolic mathematics (use SymPy)
- Data manipulation (use pandas)
Quick Reference
Installation
pip install scipy
conda install scipy
pip install numpy scipy
Standard Imports
import numpy as np
from scipy import integrate, optimize, interpolate
from scipy import linalg, signal, stats
from scipy.integrate import odeint, solve_ivp
from scipy.optimize import minimize, root
from scipy.interpolate import interp1d, UnivariateSpline
Basic Pattern - Integration
from scipy import integrate
import numpy as np
def f(x):
return x**2
result, error = integrate.quad(f, 0, 1)
print(f"Integral: {result:.6f} ± {error:.2e}")
Basic Pattern - Optimization
from scipy import optimize
import numpy as np
def f(x):
return (x - 2)**2 + 1
result = optimize.minimize(f, x0=0)
print(f"Minimum at x = {result.x[0]:.6f}")
print(f"Minimum value = {result.fun:.6f}")
Basic Pattern - Interpolation
from scipy import interpolate
import numpy as np
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 1, 4, 9, 16])
f = interpolate.interp1d(x, y, kind='cubic')
x_new = np.linspace(0, 4, 100)
y_new = f(x_new)
Critical Rules
✅ DO
- Check convergence - Always verify optimization converged
- Specify tolerances - Set appropriate
rtol and atol
- Use appropriate methods - Choose algorithm for problem type
- Validate inputs - Check array shapes and values
- Handle edge cases - Deal with singularities and discontinuities
- Set integration limits carefully - Watch for infinite limits
- Use vectorization - Functions should accept arrays
- Check statistical assumptions - Verify distribution assumptions
- Specify degrees of freedom - For interpolation and fitting
- Use sparse matrices - For large, sparse systems
❌ DON'T
- Ignore convergence warnings - They indicate problems
- Use inappropriate tolerances - Too loose or too tight
- Apply wrong distribution - Check data characteristics
- Forget initial guesses - Optimization needs good starting points
- Integrate discontinuous functions - Without special handling
- Extrapolate beyond data - Interpolation is not extrapolation
- Mix incompatible units - Keep consistent units
- Ignore error estimates - They provide confidence levels
- Use wrong coordinate system - Check Cartesian vs polar
- Overfit with high-degree polynomials - Causes oscillations
Anti-Patterns (NEVER)
from scipy import integrate, optimize
import numpy as np
result = optimize.minimize(f, x0=0)
optimal_x = result.x
result = optimize.minimize(f, x0=0)
if result.success:
optimal_x = result.x
else:
print(f"Optimization failed: {result.message}")
def bad_func(x):
if x < 0.5:
return x
else:
return 1 - x
def good_func(x):
return np.where(x < 0.5, x, 1 - x)
result = optimize.minimize(complex_func, x0=[1000, 1000])
x0 = np.array([0.0, 0.0])
result = optimize.minimize(complex_func, x0=x0)
f = interpolate.interp1d(x_data, y_data)
y_new = f(100)
f = interpolate.interp1d(x_data, y_data, fill_value='extrapolate')
y_new = f()
stats.ttest_ind(non_normal_data1, non_normal_data2)
stats.mannwhitneyu(non_normal_data1, non_normal_data2)
Integration (scipy.integrate)
Numerical Integration (Quadrature)
from scipy import integrate
import numpy as np
def f(x):
return np.exp(-x**2)
result, error = integrate.quad(f, 0, np.inf)
print(f"∫exp(-x²)dx from 0 to ∞ = {result:.6f}")
print(f"Error estimate: {error:.2e}")
def g(x, a, b):
return a * x**2 + b
result, error = integrate.quad(g, 0, 1, args=(2, 3))
print(f"Result: {result:.6f}")
def h(x):
return 1 / np.sqrt(x)
result, error = integrate.quad(h, 0, 1, points=[0])
Double and Triple Integrals
from scipy import integrate
import numpy as np
def f(y, x):
return x * y
result, error = integrate.dblquad(f, 0, 1, 0, 2)
print(f"Double integral: {result:.6f}")
def g(z, y, x):
return x * y * z
result, error = integrate.tplquad(g, 0, 1, 0, 1, 0, 1)
print(f"Triple integral: {result:.6f}")
def lower(x):
return 0
def upper(x):
return x
result, error = integrate.dblquad(f, 0, 1, lower, upper)
Solving ODEs
from scipy.integrate import odeint, solve_ivp
import numpy as np
def exponential_decay(y, t, k):
return -k * y
y0 = 100
t = np.linspace(0, 10, 100)
k = 0.5
solution = odeint(exponential_decay, y0, t, args=(k,))
def decay_ivp(t, y, k):
return -k * y
sol = solve_ivp(decay_ivp, [0, 10], [y0], args=(k,), t_eval=t)
print(f"Final value (odeint): {solution[-1, 0]:.6f}")
print(f"Final value (solve_ivp): {sol.y[0, -1]:.6f}")
System of ODEs
from scipy.integrate import solve_ivp
import numpy as np
def lotka_volterra(t, z, a, b, c, d):
x, y = z
dxdt = a*x - b*x*y
dydt = -c*y + d*x*y
return [dxdt, dydt]
a, b, c, d = 1.5, 1.0, 3.0, 1.0
z0 = [10, 5]
t_span = (0, 15)
t_eval = np.linspace(0, 15, 1000)
sol = solve_ivp(lotka_volterra, t_span, z0, args=(a, b, c, d),
t_eval=t_eval, method='RK45')
prey = sol.y[0]
predator = sol.y[1]
print(f"Prey population at t=15: {prey[-1]:.2f}")
print(f"Predator population at t=15: {predator[-1]:.2f}")
Optimization (scipy.optimize)
Function Minimization
from scipy import optimize
import numpy as np
def rosenbrock(x):
return (1 - x[0])**2 + 100*(x[1] - x[0]**2)**2
x0 = np.array([0, 0])
result = optimize.minimize(rosenbrock, x0, method='Nelder-Mead')
print(f"Nelder-Mead: x = {result.x}, f(x) = {result.fun:.6f}")
result = optimize.minimize(rosenbrock, x0, method='BFGS')
print(f"BFGS: x = {result.x}, f(x) = {result.fun:.6f}")
bounds = [(0, 2), (0, 2)]
result = optimize.minimize(rosenbrock, x0, method='L-BFGS-B', bounds=bounds)
print(f"L-BFGS-B with bounds: x = {result.x}")
Root Finding
from scipy import optimize
import numpy as np
def f(x):
return x**3 - 2*x - 5
root = optimize.brentq(f, 0, 3)
print(f"Root: {root:.6f}")
def f_prime(x):
return 3*x**2 - 2
root = optimize.newton(f, x0=2, fprime=f_prime)
print(f"Root (Newton): {root:.6f}")
def system(x):
return [x[0]**2 + x[1]**2 - 1,
x[0] - x[1]]
result = optimize.root(system, [1, 1])
print(f"Solution: {result.x}")
Curve Fitting
from scipy import optimize
import numpy as np
x_data = np.linspace(0, 10, 50)
y_true = 2.5 * np.exp(-0.5 * x_data)
y_data = y_true + 0.2 * np.random.randn(len(x_data))
def exponential_model(x, a, b):
return a * np.exp(b * x)
params, covariance = optimize.curve_fit(exponential_model, x_data, y_data)
a_fit, b_fit = params
print(f"Fitted parameters: a = {a_fit:.4f}, b = {b_fit:.4f}")
print(f"True parameters: a = 2.5, b = -0.5")
perr = np.sqrt(np.diag(covariance))
print(f"Parameter errors: ±{perr}")
Constrained Optimization
from scipy import optimize
import numpy as np
def objective(x):
return x[0]**2 + x[1]**2
def constraint(x):
return x[0] + x[1] - 1
con = {'type': 'ineq', 'fun': constraint}
x0 = np.array([2, 2])
result = optimize.minimize(objective, x0, constraints=con)
print(f"Optimal point: {result.x}")
print(f"Objective value: {result.fun:.6f}")
Interpolation (scipy.interpolate)
1D Interpolation
from scipy import interpolate
import numpy as np
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([0, 0.8, 0.9, 0.1, -0.8, -1])
f_linear = interpolate.interp1d(x, y, kind='linear')
f_cubic = interpolate.interp1d(x, y, kind='cubic')
x_new = np.linspace(0, 5, 100)
y_linear = f_linear(x_new)
y_cubic = f_cubic(x_new)
print(f"Value at x=2.5 (linear): {f_linear(2.5):.4f}")
print(f"Value at x=2.5 (cubic): {f_cubic(2.5):.4f}")
Spline Interpolation
from scipy import interpolate
import numpy as np
x = np.linspace(0, 10, 11)
y = np.sin(x)
tck = interpolate.splrep(x, y, s=0)
x_new = np.linspace(0, 10, 100)
y_new = interpolate.splev(x_new, tck)
spl = interpolate.UnivariateSpline(x, y, s=0)
y_spl = spl(x_new)
spl_smooth = interpolate.UnivariateSpline(x, y, s=1)
y_smooth = spl_smooth(x_new)
2D Interpolation
from scipy import interpolate
import numpy as np
x = np.linspace(0, 4, 5)
y = np.linspace(0, 4, 5)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
x_flat = X.flatten()
y_flat = Y.flatten()
z_flat = Z.flatten()
f = interpolate.interp2d(x_flat, y_flat, z_flat, kind='cubic')
x_new = np.linspace(0, 4, 50)
y_new = np.linspace(0, 4, 50)
Z_new = f(x_new, y_new)
print(f"Interpolated shape: {Z_new.shape}")
Linear Algebra (scipy.linalg)
Advanced Matrix Operations
from scipy import linalg
import numpy as np
A = np.array([[1, 2], [3, 4]])
exp_A = linalg.expm(A)
log_A = linalg.logm(A)
sqrt_A = linalg.sqrtm(A)
A_power_3 = linalg.fractional_matrix_power(A, 3)
print(f"exp(A):\n{exp_A}")
print(f"A^3:\n{A_power_3}")
Matrix Decompositions
from scipy import linalg
import numpy as np
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 10]])
P, L, U = linalg.lu(A)
print(f"A = P @ L @ U: {np.allclose(A, P @ L @ U)}")
Q, R = linalg.qr(A)
print(f"A = Q @ R: {np.allclose(A, Q @ R)}")
A_pos_def = np.array([[4, 2], [2, 3]])
L = linalg.cholesky(A_pos_def, lower=True)
print(f"A = L @ L.T: {np.allclose(A_pos_def, L @ L.T)}")
T, Z = linalg.schur(A)
print(f"A = Z @ T @ Z.H: {np.allclose(A, Z @ T @ Z.T.conj())}")
Sparse Matrices
from scipy import sparse
import numpy as np
row = np.array([0, 0, 1, 2, 2, 2])
col = np.array([0, 2, 2, 0, 1, 2])
data = np.array([1, 2, 3, 4, 5, 6])
A_coo = sparse.coo_matrix((data, (row, col)), shape=(3, 3))
A_csr = A_coo.tocsr()
A_dense = A_csr.toarray()
print(f"Dense matrix:\n{A_dense}")
B = sparse.eye(3)
C = A_csr + B
D = A_csr @ B
print(f"Number of non-zeros: {A_csr.nnz}")
print(f"Sparsity: {1 - A_csr.nnz / (3*3):.2%}")
Signal Processing (scipy.signal)
Filter Design
from scipy import signal
import numpy as np
b, a = signal.butter(4, 0.5, btype='low')
t = np.linspace(0, 1, 1000)
sig = np.sin(2*np.pi*5*t) + 0.5*np.sin(2*np.pi*50*t)
filtered = signal.filtfilt(b, a, sig)
b_cheby, a_cheby = signal.cheby1(4, 0.5, 0.5)
w, h = signal.freqz(b, a)
print(f"Filter order: {len(b)-1}")
Convolution and Correlation
from scipy import signal
import numpy as np
sig1 = np.array([1, 2, 3, 4, 5])
sig2 = np.array([0, 1, 0.5])
conv = signal.convolve(sig1, sig2, mode='same')
print(f"Convolution: {conv}")
corr = signal.correlate(sig1, sig2, mode='same')
print(f"Correlation: {corr}")
image = np.random.rand(100, 100)
kernel = np.array([[1, 0, -1],
[2, 0, -2],
[1, 0, -1]]) / 4
filtered_img = signal.convolve2d(image, kernel, mode='same')
Peak Finding
from scipy import signal
import numpy as np
t = np.linspace(0, 10, 1000)
sig = np.sin(2*np.pi*t) + 0.5*np.sin(2*np.pi*5*t)
peaks, properties = signal.find_peaks(sig, height=0.5, distance=50)
print(f"Found {len(peaks)} peaks")
print(f"Peak positions: {peaks[:5]}")
print(f"Peak heights: {properties['peak_heights'][:5]}")
peaks_width, properties_width = signal.find_peaks(sig, width=20)
widths = properties_width['widths']
Spectral Analysis
from scipy import signal
import numpy as np
fs = 1000
t = np.linspace(0, 1, fs)
sig = np.sin(2*np.pi*50*t) + np.sin(2*np.pi*120*t)
f, Pxx = signal.periodogram(sig, fs)
f_welch, Pxx_welch = signal.welch(sig, fs, nperseg=256)
f_spec, t_spec, Sxx = signal.spectrogram(sig, fs)
print(f"Frequency resolution: {f[1] - f[0]:.2f} Hz")
print(f"Number of frequency bins: {len(f)}")
Statistics (scipy.stats)
Probability Distributions
from scipy import stats
import numpy as np
mu, sigma = 0, 1
norm = stats.norm(loc=mu, scale=sigma)
x = np.linspace(-3, 3, 100)
pdf = norm.pdf(x)
cdf = norm.cdf(x)
ppf = norm.ppf(0.975)
print(f"P(X ≤ 1.96) = {norm.cdf(1.96):.4f}")
print(f"97.5th percentile: {ppf:.4f}")
samples = norm.rvs(size=1000)
exponential = stats.expon(scale=2)
poisson = stats.poisson(mu=5)
binomial = stats.binom(n=10, p=0.5)
Hypothesis Testing
from scipy import stats
import numpy as np
np.random.seed(42)
sample1 = stats.norm.rvs(loc=0, scale=1, size=100)
sample2 = stats.norm.rvs(loc=0.5, scale=1, size=100)
t_stat, p_value = stats.ttest_ind(sample1, sample2)
print(f"t-test: t = {t_stat:.4f}, p = {p_value:.4f}")
u_stat, p_value_mw = stats.mannwhitneyu(sample1, sample2)
print(f"Mann-Whitney: U = {u_stat:.4f}, p = {p_value_mw:.4f}")
observed = np.array([10, 20, 30, 40])
expected = np.array([25, 25, 25, 25])
chi2, p_chi = stats.chisquare(observed, expected)
print(f"Chi-square: χ² = {chi2:.4f}, p = {p_chi:.4f}")
ks_stat, p_ks = stats.kstest(sample1, 'norm')
print(f"KS test: D = {ks_stat:.4f}, p = {p_ks:.4f}")
Correlation and Regression
from scipy import stats
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = 2*x + 1 + np.random.randn(10)*0.5
r, p_value = stats.pearsonr(x, y)
print(f"Pearson r = {r:.4f}, p = {p_value:.4f}")
rho, p_spear = stats.spearmanr(x, y)
print(f"Spearman ρ = {rho:.4f}, p = {p_spear:.4f}")
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
print(f"y = {slope:.4f}x + {intercept:.4f}")
print(f"R² = {r_value**2:.4f}")
Fast Fourier Transform (scipy.fft)
Basic FFT
from scipy import fft
import numpy as np
fs = 1000
T = 1/fs
N = 1000
t = np.linspace(0, N*T, N)
signal = np.sin(2*np.pi*50*t) + 0.5*np.sin(2*np.pi*120*t)
yf = fft.fft(signal)
xf = fft.fftfreq(N, T)
magnitude = np.abs(yf)
positive_freq_idx = xf > 0
xf_positive = xf[positive_freq_idx]
magnitude_positive = magnitude[positive_freq_idx]
print(f"Peak frequencies: {xf_positive[magnitude_positive > 100]}")
Inverse FFT
from scipy import fft
import numpy as np
t = np.linspace(0, 1, 1000)
signal = np.sin(2*np.pi*10*t)
signal_fft = fft.fft(signal)
signal_fft[100:] = 0
signal_filtered = fft.ifft(signal_fft).real
print(f"Signal reconstructed: {np.allclose(signal[:100], signal_filtered[:100])}")
2D FFT (for images)
from scipy import fft
import numpy as np
x = np.linspace(0, 2*np.pi, 128)
y = np.linspace(0, 2*np.pi, 128)
X, Y = np.meshgrid(x, y)
image = np.sin(5*X) * np.cos(5*Y)
image_fft = fft.fft2(image)
image_fft_shifted = fft.fftshift(image_fft)
magnitude = np.abs(image_fft_shifted)
image_reconstructed = fft.ifft2(image_fft).real
print(f"Image shape: {image.shape}")
print(f"FFT shape: {image_fft.shape}")
Spatial Algorithms (scipy.spatial)
Distance Computations
from scipy.spatial import distance
import numpy as np
p1 = np.array([0, 0])
p2 = np.array([3, 4])
eucl = distance.euclidean(p1, p2)
print(f"Euclidean distance: {eucl:.4f}")
manh = distance.cityblock(p1, p2)
print(f"Manhattan distance: {manh:.4f}")
cosine = distance.cosine(p1, p2)
points = np.random.rand(10, 2)
dist_matrix = distance.cdist(points, points, 'euclidean')
print(f"Distance matrix shape: {dist_matrix.shape}")
Convex Hull
from scipy.spatial import ConvexHull
import numpy as np
points = np.random.rand(30, 2)
hull = ConvexHull(points)
print(f"Number of vertices: {len(hull.vertices)}")
print(f"Hull area: {hull.area:.4f}")
print(f"Hull volume (perimeter): {hull.volume:.4f}")
hull_points = points[hull.vertices]
Delaunay Triangulation
from scipy.spatial import Delaunay
import numpy as np
points = np.random.rand(30, 2)
tri = Delaunay(points)
print(f"Number of triangles: {len(tri.simplices)}")
test_point = np.array([0.5, 0.5])
simplex_index = tri.find_simplex(test_point)
print(f"Point inside: {simplex_index >= 0}")
KDTree for Nearest Neighbors
from scipy.spatial import KDTree
import numpy as np
points = np.random.rand(100, 3)
tree = KDTree(points)
query_point = np.array([0.5, 0.5, 0.5])
distances, indices = tree.query(query_point, k=5)
print(f"5 nearest neighbors:")
print(f"Distances: {distances}")
print(f"Indices: {indices}")
indices_radius = tree.query_ball_point(query_point, r=0.3)
print(f"Points within r=0.3: {len(indices_radius)}")
Practical Workflows
Numerical Integration of Physical System
from scipy.integrate import odeint
import numpy as np
def damped_oscillator(y, t, m, c, k):
x, v = y
dxdt = v
dvdt = -(c/m)*v - (k/m)*x
return [dxdt, dvdt]
m = 1.0
c = 0.5
k = 10.0
y0 = [1.0, 0.0]
t = np.linspace(0, 10, 1000)
solution = odeint(damped_oscillator, y0, t, args=(m, c, k))
position = solution[:, 0]
velocity = solution[:, 1]
print(f"Final position: {position[-1]:.6f}")
print(f"Final velocity: {velocity[-1]:.6f}")
Parameter Estimation from Data
from scipy import optimize
import numpy as np
x_true = np.linspace(0, 10, 50)
params_true = [2.5, 1.3, 0.8]
y_true = params_true[0] * np.exp(-params_true[1] * x_true) + params_true[2]
y_data = y_true + 0.2 * np.random.randn(len(x_true))
def model(x, a, b, c):
return a * np.exp(-b * x) + c
def objective(params):
y_pred = model(x_true, *params)
return np.sum((y_data - y_pred)**2)
params_init = [1.0, 1.0, 1.0]
result = optimize.minimize(objective, params_init)
print(f"True parameters: {params_true}")
print(f"Estimated parameters: {result.x}")
print(f"Relative errors: {np.abs(result.x - params_true) / params_true * 100}%")
Signal Filtering Pipeline
from scipy import signal
import numpy as np
def filter_pipeline(noisy_signal, fs):
"""Complete signal processing pipeline."""
fc = 10
w = fc / (fs / 2)
b, a = signal.butter(4, w, 'low')
filtered = signal.filtfilt(b, a, noisy_signal)
baseline = signal.medfilt(filtered, kernel_size=51)
detrended = filtered - baseline
normalized = (detrended - np.mean(detrended)) / np.std(detrended)
return normalized
fs = 1000
t = np.linspace(0, 1, fs)
clean_signal = np.sin(2*np.pi*5*t)
noise = 0.5 * np.random.randn(len(t))
drift = 0.1 * t
noisy_signal = clean_signal + noise + drift
processed = filter_pipeline(noisy_signal, fs)
print(f"Original SNR: {10*np.log10(np.var(clean_signal)/np.var(noise)):.2f} dB")
Interpolation and Smoothing
from scipy import interpolate
import numpy as np
x = np.linspace(0, 10, 20)
y_true = np.sin(x)
y_noisy = y_true + 0.3 * np.random.randn(len(x))
spl = interpolate.UnivariateSpline(x, y_noisy, s=2)
x_fine = np.linspace(0, 10, 200)
y_smooth = spl(x_fine)
y_true_fine = np.sin(x_fine)
rmse = np.sqrt(np.mean((y_smooth - y_true_fine)**2))
print(f"RMSE: {rmse:.6f}")
y_prime = spl.derivative()(x_fine)
y_double_prime = spl.derivative(n=2)(x_fine)
Statistical Analysis Workflow
from scipy import stats
import numpy as np
def analyze_experiment(control, treatment):
"""Complete statistical analysis of experiment data."""
results = {}
results['control_mean'] = np.mean(control)
results['treatment_mean'] = np.mean(treatment)
results['control_std'] = np.std(control, ddof=1)
results['treatment_std'] = np.std(treatment, ddof=1)
_, results['control_normal_p'] = stats.shapiro(control)
_, results['treatment_normal_p'] = stats.shapiro(treatment)
if results['control_normal_p'] > 0.05 and results['treatment_normal_p'] > 0.05:
t_stat, p_value = stats.ttest_ind(control, treatment)
results['test'] = 't-test'
results['statistic'] = t_stat
results['p_value'] = p_value
else:
u_stat, p_value = stats.mannwhitneyu(control, treatment)
results['test'] = 'Mann-Whitney U'
results['statistic'] = u_stat
results['p_value'] = p_value
pooled_std = np.sqrt((results['control_std']**2 +
results['treatment_std']**) / )
results[] = ((results[] -
results[]) / pooled_std)
results
control = stats.norm.rvs(loc=, scale=, size=)
treatment = stats.norm.rvs(loc=, scale=, size=)
results = analyze_experiment(control, treatment)
()
()
()
Performance Optimization
Choosing the Right Method
from scipy import integrate, optimize
import numpy as np
import time
def f(x):
return np.exp(-x**2)
methods = ['quad', 'romberg', 'simpson']
times = []
for method in methods:
start = time.time()
if method == 'quad':
result, _ = integrate.quad(f, 0, 10)
elif method == 'romberg':
x = np.linspace(0, 10, 1000)
result = integrate.romberg(f, 0, 10)
elif method == 'simpson':
x = np.linspace(0, 10, 1000)
y = f(x)
result = integrate.simpson(y, x)
elapsed = time.time() - start
times.append(elapsed)
print(f"{method}: {result:.8f} ({elapsed*1000:.2f} ms)")
Vectorization
from scipy import interpolate
import numpy as np
def interpolate_loop(x, y, x_new):
results = []
for xi in x_new:
f = interpolate.interp1d(x, y)
results.append(f(xi))
return np.array(results)
def interpolate_vectorized(x, y, x_new):
f = interpolate.interp1d(x, y)
return f(x_new)
x = np.linspace(0, 10, 100)
y = np.sin(x)
x_new = np.linspace(0, 10, 1000)
result = interpolate_vectorized(x, y, x_new)
Common Pitfalls and Solutions
Integration Convergence
from scipy import integrate
import numpy as np
def oscillatory(x):
return np.sin(100*x) / x if x != 0 else 100
result, error = integrate.quad(oscillatory, 0, 1)
result, error = integrate.quad(oscillatory, 0, 1,
limit=100, epsabs=1e-10, epsrel=1e-10)
from scipy.integrate import quad_vec
result, error = quad_vec(oscillatory, 0, 1)
Optimization Local Minima
from scipy import optimize
import numpy as np
def multi_minima(x):
return np.sin(x) + np.sin(10*x/3)
result = optimize.minimize(multi_minima, x0=0)
print(f"Local minimum: {result.x[0]:.4f}")
x0_list = np.linspace(0, 10, 20)
results = [optimize.minimize(multi_minima, x0=x0) for x0 in x0_list]
global_min = min(results, key=lambda r: r.fun)
print(f"Global minimum: {global_min.x[0]:.4f}")
result_global = optimize.differential_evolution(multi_minima, bounds=[(0, 10)])
print(f"Global (DE): {result_global.x[0]:.4f}")
Statistical Test Assumptions
from scipy import stats
import numpy as np
non_normal = stats.expon.rvs(size=30)
t_stat, p_value = stats.ttest_1samp(non_normal, 1.0)
_, p_normal = stats.shapiro(non_normal)
if p_normal < 0.05:
print("Data is not normal, using Wilcoxon test")
stat, p_value = stats.wilcoxon(non_normal - 1.0)
else:
t_stat, p_value = stats.ttest_1samp(non_normal, 1.0)
Sparse Matrix Efficiency
from scipy import sparse
import numpy as np
import time
n = 10000
density = 0.01
data = np.random.rand(int(n*n*density))
row = np.random.randint(0, n, len(data))
col = np.random.randint(0, n, len(data))
A_coo = sparse.coo_matrix((data, (row, col)), shape=(n, n))
A_csr = A_coo.tocsr()
A_csc = A_coo.tocsc()
x = np.random.rand(n)
y = A_csr @ x
print(f"Sparse matrix: {A_csr.nnz / (n*n) * 100:.2f}% non-zero")
This comprehensive SciPy guide covers 50+ examples across all major scientific computing workflows!