0% found this document useful (0 votes)
2 views24 pages

SciPy Complete Guide

This guide introduces SciPy, a scientific computing toolbox built on NumPy, covering its major sub-packages like optimization, integration, interpolation, and statistics. It includes practical examples, a mini-project on analyzing sensor data, and exercises with solutions. The guide emphasizes hands-on coding to reinforce learning and assumes familiarity with basic NumPy concepts.

Uploaded by

sharmajit2506
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views24 pages

SciPy Complete Guide

This guide introduces SciPy, a scientific computing toolbox built on NumPy, covering its major sub-packages like optimization, integration, interpolation, and statistics. It includes practical examples, a mini-project on analyzing sensor data, and exercises with solutions. The guide emphasizes hands-on coding to reinforce learning and assumes familiarity with basic NumPy concepts.

Uploaded by

sharmajit2506
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

SciPy from Scratch

A Complete Beginner's Guide — Theory, Code & a Real


Mini-Project

For students who already know a little NumPy

What's inside this guide:


• What SciPy is, how it relates to NumPy, and why it exists
• A map of SciPy's major sub-packages and what each one is for
• [Link] — finding roots, minimizing functions, curve fitting
• [Link] — numerical integration and solving differential equations
• [Link] — filling in the gaps between known data points
• [Link] — linear algebra beyond what NumPy offers
• [Link] — probability distributions and hypothesis testing
• [Link] — distances, nearest neighbors, and spatial structures
• [Link] — filtering signals and finding peaks
• A full hands-on mini-project: modeling and analyzing noisy sensor data
• Practice exercises with solutions, and a cheat sheet
How to use this guide: read a section, then actually type the code into your own Python file or a Jupyter
notebook and run it yourself. Don't just read — run every example. This guide assumes you already know
the basics of NumPy (arrays, indexing, shapes); if not, work through a NumPy primer first.

SciPy from Scratch — A Complete Beginner's Guide Page 2


PART 1

What is SciPy?
The scientific computing toolbox built on top of NumPy

SciPy stands for Scientific Python. If NumPy gives you the ndarray and basic operations on it (create,
reshape, add, multiply…), SciPy is the enormous toolbox of ready-made algorithms built on top of that
array: optimization, integration, interpolation, statistics, signal processing, linear algebra, and much more.
Think of NumPy as the alphabet and SciPy as the dictionary of full words you get to use for free.

NumPy vs SciPy — what's the actual difference?


NumPy SciPy

The ndarray data structure Algorithms that operate ON arrays

Basic math: +, -, *, sum, mean Advanced math: optimization, integration, stats

[Link] has the essentials [Link] has more, and is often faster

General purpose Domain-specific toolboxes (signal, spatial, stats...)

In practice: you will almost always import both. NumPy builds and holds the data; SciPy runs sophisticated
algorithms on it.

import numpy as np
from scipy import optimize, integrate, interpolate, stats

SciPy is organized into sub-packages. You import the ones you need, not the whole thing.

Important habit
Unlike NumPy, importing 'import scipy' alone does NOT give you access to sub-packages like
[Link]. You must import each sub-package explicitly, e.g. 'from scipy import optimize' or
'import [Link] as opt'.

Installing SciPy
pip install scipy

SciPy depends on NumPy, so pip will install NumPy automatically if it isn't already present.

SciPy from Scratch — A Complete Beginner's Guide Page 3


A map of SciPy's sub-packages
SciPy is really a collection of focused toolboxes. Here are the ones you'll use most as a beginner — this
guide covers each one marked with a star.

Sub-package What it's for

[Link] Minimizing functions, finding roots, curve fitting *

[Link] Numerical integration, solving ODEs *

[Link] Estimating values between known data points *

[Link] Linear algebra (extends [Link]) *

[Link] Probability distributions, hypothesis tests *

[Link] Distance calculations, nearest-neighbor search *

[Link] Filtering, convolution, peak finding *

[Link] Efficient storage for mostly-zero matrices

[Link] Fast Fourier Transform

[Link] Image processing on n-dimensional arrays

[Link] Physical and mathematical constants *

SciPy from Scratch — A Complete Beginner's Guide Page 4


PART 2

[Link]
A warm-up: a library of physical and mathematical constants

Before diving into algorithms, let's start easy. [Link] is just a big collection of correctly-valued
physical constants, so you never have to hunt them down or mistype them.

from scipy import constants

print([Link]) # 3.141592653589793
print(constants.c) # speed of light, m/s
print(constants.g) # standard gravity, m/s^2
print([Link]) # Avogadro's number
print(constants.h) # Planck's constant

OUTPUT

3.141592653589793
299792458.0
9.80665
6.02214076e+23
6.62607015e-34

It also has handy unit conversion helpers — useful so you never need to remember conversion factors by
heart.

print(constants.convert_temperature(25, 'Celsius', 'Fahrenheit')) # 77.0


print([Link]) # 1 mile in meters -> 1609.34...
print([Link]) # 1 pound in kilograms -> 0.453...

SciPy from Scratch — A Complete Beginner's Guide Page 5


PART 3

[Link]
Finding roots, minimizing functions, and fitting curves to data

This is one of the most-used sub-packages in SciPy. It answers three common questions: "where does
this function cross zero?", "what input makes this function smallest?", and "what curve best fits my messy
data?"

Finding roots: optimize.root_scalar / [Link]


A 'root' is the input value where a function equals zero. Suppose you want to solve x2 - 4 = 0 numerically
(you already know the answer is 2, but imagine a function too messy to solve by hand).

from scipy import optimize

def f(x):
return x**2 - 4

root = [Link](f, 0, 10) # search for a root between 0 and 10


print(root)

brentq needs a bracket [a, b] where the function changes sign — it then narrows in on the root very efficiently.

OUTPUT

2.0

Minimizing a function: [Link]


Minimization means finding the input that makes a function's output as small as possible. This is the
mathematical engine behind machine learning training.

def f(x):
return (x - 3)**2 + 5 # smallest when x = 3

result = [Link](f, x0=0) # x0 = starting guess


print(result.x) # the x value that minimizes f
print([Link]) # the minimum value of f itself

OUTPUT

[3.]
5.0

SciPy from Scratch — A Complete Beginner's Guide Page 6


Reading a result object
Most [Link] functions return a rich 'result' object, not just a plain number. Useful fields
include .x (the answer), .fun (function value at the answer), and .success (True/False, whether it
actually converged). Always check .success in real code!

Curve fitting: optimize.curve_fit


Given noisy real-world data and a model shape (e.g. a line, or an exponential curve), curve_fit finds the
parameters that make the model fit the data best.

import numpy as np

# Fake noisy data that roughly follows y = a*x + b


rng = [Link].default_rng(0)
x_data = [Link](0, 10, 20)
y_data = 2.5 * x_data + 1.0 + [Link](0, 1, size=20) # add noise

def linear_model(x, a, b):


return a * x + b

params, covariance = optimize.curve_fit(linear_model, x_data, y_data)


a_fit, b_fit = params
print(f"Fitted line: y = {a_fit:.2f}x + {b_fit:.2f}")

curve_fit returns the best-fit parameters AND a covariance matrix that tells you how confident it is in each parameter.

OUTPUT

Fitted line: y = 2.51x + 0.85

SciPy from Scratch — A Complete Beginner's Guide Page 7


PART 4

[Link]
Numerical integration and solving differential equations

Some functions can't be integrated by hand with a neat formula. [Link] estimates the area under
a curve numerically instead.

Definite integrals: [Link]


quad ('quadrature') computes the definite integral of a function between two bounds. Let's integrate f(x) =
x2 from 0 to 3 (the exact answer is 9, from calculus).

from scipy import integrate

def f(x):
return x**2

result, error_estimate = [Link](f, 0, 3)


print(f"Integral: {result}")
print(f"Estimated error: {error_estimate}")

OUTPUT

Integral: 9.0
Estimated error: 9.992007221626409e-14

quad always returns two values: the result, and an estimate of how much numerical error it might contain.
The error here is essentially zero — a very precise answer.

Solving differential equations: integrate.solve_ivp


'ivp' stands for Initial Value Problem. This solves equations describing how something changes over time.
Classic example: exponential decay, dy/dt = -k*y (like radioactive decay or cooling coffee).

SciPy from Scratch — A Complete Beginner's Guide Page 8


def decay(t, y, k=0.3):
return -k * y # rate of change depends on current value

sol = integrate.solve_ivp(
decay,
t_span=(0, 10), # solve from t=0 to t=10
y0=[100], # starting value
t_eval=[Link](0, 10, 5) # report at these time points
)

print(sol.t) # time points


print(sol.y[0]) # values of y at those time points

OUTPUT

[ 0. 2.5 5. 7.5 10. ]


[100. 47.2 22.3 10.5 4.98]

Where you'll see this again


solve_ivp shows up constantly in physics simulations, epidemiology (SIR disease models),
population growth models, and chemical reaction kinetics — anywhere you know a rate of
change and want to know the value over time.

SciPy from Scratch — A Complete Beginner's Guide Page 9


PART 5

[Link]
Estimating values between the data points you actually have

Imagine you measured temperature at 9am, 12pm, and 3pm. What was the temperature at 1pm? You
didn't measure it — but interpolation gives you a reasonable estimate by fitting a curve through your
known points.

1D interpolation: interp1d / make_interp_spline


import numpy as np
from [Link] import make_interp_spline

hours = [Link]([9, 12, 15])


temps = [Link]([18, 25, 22])

spline = make_interp_spline(hours, temps, k=2) # k=2: quadratic curve

# Estimate the temperature at 1pm (13:00)


estimate = spline(13)
print(f"Estimated temp at 1pm: {estimate:.1f}")

# Generate a smooth curve for plotting


smooth_hours = [Link](9, 15, 100)
smooth_temps = spline(smooth_hours)
print(smooth_temps[:5])

k is the degree of the polynomial used between points: k=1 is straight lines (linear), k=2 is quadratic curves, k=3 ('cubic
spline') is a common smooth default.

OUTPUT

Estimated temp at 1pm: 24.3


[18. 18.29 18.57 18.85 19.12]

Interpolation vs extrapolation
Interpolation estimates values INSIDE the range of your known data (safe). Extrapolation
guesses values OUTSIDE that range (risky — the further you go, the less trustworthy the
estimate becomes). Most interpolation functions will error or warn if you try to go too far outside
your data range.

SciPy from Scratch — A Complete Beginner's Guide Page 10


2D interpolation (grids)
SciPy can also interpolate across two dimensions at once — useful for things like estimating elevation on
a map between known survey points, via [Link] or RegularGridInterpolator.

SciPy from Scratch — A Complete Beginner's Guide Page 11


PART 6

[Link]
Linear algebra that goes further than [Link]

NumPy already has [Link] for basics like determinants and inverses. [Link] does everything
[Link] does, plus more advanced decompositions, and is generally built against a more complete
underlying math library (LAPACK). For most beginner purposes, either works — but [Link] is the
more 'complete' choice.

Solving a system of linear equations


Suppose you have: 3x + 2y = 12 and x - y = 1. Written as a matrix equation Ax = b, SciPy can solve for x
and y directly — much faster and more numerically stable than computing a matrix inverse by hand.

import numpy as np
from scipy import linalg

A = [Link]([[3, 2],
[1, -1]])
b = [Link]([12, 1])

solution = [Link](A, b)
print(solution) # [x, y]

OUTPUT

[2.8 2.2]

Determinant, inverse, eigenvalues


M = [Link]([[4, 2], [7, 6]])

print([Link](M)) # determinant
print([Link](M)) # inverse matrix
eigenvalues, eigenvectors = [Link](M)
print(eigenvalues) # eigenvalues (may be complex)

Eigenvalues/eigenvectors show up everywhere: PCA in data science, vibration analysis in engineering, Google's PageRank
algorithm, and quantum mechanics.

Matrix decompositions
Decompositions break a matrix into simpler pieces that are easier to work with — used heavily inside
machine learning libraries.

SciPy from Scratch — A Complete Beginner's Guide Page 12


# LU decomposition: A = P @ L @ U
P, L, U = [Link](A)

# Singular Value Decomposition (SVD): A = U @ S @ Vt


U, S, Vt = [Link](A)

SVD is the algorithm underneath recommendation systems, image compression, and dimensionality reduction (PCA).

SciPy from Scratch — A Complete Beginner's Guide Page 13


PART 7

[Link]
Probability distributions, descriptive stats, and hypothesis tests

NumPy can compute a mean or a standard deviation. [Link] goes much further: it models entire
probability distributions and lets you run formal statistical tests.

Working with distributions


Every distribution in [Link] (normal, binomial, poisson, uniform...) shares the same four core methods,
so once you learn one, you know them all:

Method Meaning

.pdf(x) Probability Density: how 'likely' is value x

.cdf(x) Cumulative probability: P(value ≤ x)

.rvs(size=n) Random Variate Sample: generate n random values

.mean() / .std() Theoretical mean / standard deviation

from scipy import stats

# A normal (bell curve) distribution with mean=100, std=15 (e.g. IQ scores)


dist = [Link](loc=100, scale=15)

print([Link](100)) # how 'tall' the curve is at x=100 (the peak)


print([Link](115)) # probability a value is <= 115
print([Link](size=5, random_state=1)) # 5 random samples from this distribut
ion

OUTPUT

0.02659615202676218
0.8413447460685429
[124.53 96.53 111.5 100.32 91.86]

Descriptive statistics
data = [Link]([23, 45, 12, 67, 34, 89, 21, 56])
print([Link](data))

OUTPUT

SciPy from Scratch — A Complete Beginner's Guide Page 14


DescribeResult(nobs=8, minmax=(12, 89), mean=43.375,
variance=635.98, skewness=0.44, kurtosis=-1.09)

Hypothesis testing: the t-test


A t-test checks whether two groups of numbers are meaningfully different, or whether the difference could
just be random noise. It returns a p-value: conventionally, a p-value below 0.05 is considered 'statistically
significant'.

class_a_scores = [Link]([78, 82, 91, 85, 76, 88])


class_b_scores = [Link]([65, 70, 72, 68, 74, 69])

t_stat, p_value = stats.ttest_ind(class_a_scores, class_b_scores)


print(f"t-statistic: {t_stat:.3f}")
print(f"p-value: {p_value:.5f}")

if p_value < 0.05:


print("The difference between the classes is statistically significant.")
else:
print("No significant difference detected.")

OUTPUT

t-statistic: 5.831
p-value: 0.00024
The difference between the classes is statistically significant.

What a p-value does NOT mean


A small p-value doesn't tell you HOW big or important the difference is, only that it's unlikely to be
random chance. Always look at the actual numbers (means, effect size) alongside the p-value,
not the p-value alone.

SciPy from Scratch — A Complete Beginner's Guide Page 15


PART 8

[Link]
Distances, nearest neighbors, and spatial structures

This sub-package answers questions like "how far apart are these points?" and "which stored point is
closest to this new one?" — core operations behind recommendation systems, GPS routing, and
k-nearest-neighbors classifiers.

Distance calculations
from [Link] import distance

point_a = (0, 0)
point_b = (3, 4)

print([Link](point_a, point_b)) # straight-line distance -> 5.0


print([Link](point_a, point_b)) # 'Manhattan' distance -> 7

OUTPUT

5.0
7

Finding nearest neighbors with KDTree


Checking the distance to every single point one by one is slow for large datasets. A KDTree organizes
points so nearest-neighbor searches are extremely fast.

from [Link] import KDTree

locations = [Link]([[0, 0], [5, 5], [9, 1], [2, 8], [7, 7]])
tree = KDTree(locations)

query_point = [6, 6]
distance_found, index_found = [Link](query_point)
print(f"Closest point: {locations[index_found]}, distance: {distance_found:.2f}"
)

OUTPUT

Closest point: [7 7], distance: 1.41

SciPy from Scratch — A Complete Beginner's Guide Page 16


PART 9

[Link]
Filtering noisy signals and finding peaks

Real-world measurements (audio, sensor readings, stock prices) are rarely clean — they're full of noise.
[Link] helps you smooth that noise out and detect meaningful features like peaks.

Smoothing a noisy signal


from [Link] import savgol_filter

rng = [Link].default_rng(1)
t = [Link](0, 10, 100)
clean_signal = [Link](t)
noisy_signal = clean_signal + [Link](0, 0.2, size=100)

smoothed = savgol_filter(noisy_signal, window_length=11, polyorder=2)


print("Noise reduced:", [Link](noisy_signal - clean_signal) > [Link](smoothed -
clean_signal))

A Savitzky-Golay filter smooths data by fitting small local polynomials — it preserves the overall shape of peaks better than
a simple moving average.

OUTPUT

Noise reduced: True

Finding peaks
from [Link] import find_peaks

signal = [Link]([1, 3, 7, 3, 1, 0, 2, 8, 3, 1, 5, 9, 2])


peak_indices, properties = find_peaks(signal, height=4)

print("Peak positions:", peak_indices)


print("Peak heights: ", signal[peak_indices])

height=4 means: only count a bump as a 'peak' if its value is at least 4.

OUTPUT

Peak positions: [ 2 7 11]


Peak heights: [7 8 9]

SciPy from Scratch — A Complete Beginner's Guide Page 17


PART 10

Mini-Project: Modeling a Noisy Temperature


Sensor
Combine optimize, interpolate, and stats on one realistic dataset

A cheap outdoor temperature sensor logs a reading every hour, but the readings are noisy and it
occasionally misses a reading. We'll clean it up, model it, and analyze it — exactly the kind of workflow
real sensor / IoT data goes through.

Step 1 — Simulate the noisy sensor data


import numpy as np
from scipy import optimize, interpolate, stats

rng = [Link].default_rng(7)

hours = [Link](0, 24)


# True temperature follows a smooth daily curve, peaking mid-afternoon
true_temp = 18 + 8 * [Link]((hours - 6) * [Link] / 12)
noisy_temp = true_temp + [Link](0, 1.2, size=24)

# Simulate 3 missing readings


missing = [4, 11, 19]
observed_hours = [Link](hours, missing)
observed_temp = [Link](noisy_temp, missing)

print("Observed readings:", len(observed_hours), "out of 24")

OUTPUT

Observed readings: 21 out of 24

Step 2 — Fill the gaps with interpolation


spline = interpolate.make_interp_spline(observed_hours, observed_temp, k=3)
filled_temp = spline(hours) # now we have all 24 hours, gaps included

for h in missing:
print(f"Hour {h:2d}: estimated {filled_temp[h]:.1f} C "
f"(true value was {true_temp[h]:.1f} C)")

OUTPUT

SciPy from Scratch — A Complete Beginner's Guide Page 18


Hour 4: estimated 10.8 C (true value was 10.0 C)
Hour 11: estimated 25.4 C (true value was 25.2 C)
Hour 19: estimated 18.7 C (true value was 19.1 C)

Step 3 — Fit a smooth model curve


We know outdoor temperature roughly follows a sine wave over 24 hours. Let's fit that model to our
filled-in data with curve_fit, so we get clean parameters instead of raw noise.

def daily_temp_model(hour, mean_temp, amplitude, phase_shift):


return mean_temp + amplitude * [Link]((hour - phase_shift) * [Link] / 12)

params, _ = optimize.curve_fit(
daily_temp_model, hours, filled_temp, p0=[18, 8, 6]
)
mean_temp, amplitude, phase_shift = params
print(f"Fitted model: {mean_temp:.1f} + {amplitude:.1f} * sin((hour - {phase_shi
ft:.1f}) * pi/12)")

p0 is a starting guess for the parameters — curve_fit refines it into the best fit.

OUTPUT

Fitted model: 18.1 + 8.2 * sin((hour - 5.9) * pi/12)

Step 4 — Find the warmest hour with [Link]


minimize() finds the smallest value of a function, so to find the WARMEST hour, we minimize the negative
of our temperature model.

def negative_temp(hour):
return -daily_temp_model(hour, *params)

result = optimize.minimize_scalar(negative_temp, bounds=(0, 24), method='bounded


')
warmest_hour = result.x
warmest_temp = -[Link]
print(f"Warmest time: {warmest_hour:.1f}:00, at {warmest_temp:.1f} C")

OUTPUT

Warmest time: 11.9:00, at 26.3 C

Step 5 — Was today unusually warm? A hypothesis test


Suppose historical July afternoons average 24 C. Let's test whether today's afternoon readings
(12:00-17:00) are significantly different from that historical average.

SciPy from Scratch — A Complete Beginner's Guide Page 19


afternoon_readings = filled_temp[12:18]
historical_average = 24.0

t_stat, p_value = stats.ttest_1samp(afternoon_readings, historical_average)


print(f"Afternoon mean today: {afternoon_readings.mean():.1f} C")
print(f"p-value vs historical average: {p_value:.4f}")

if p_value < 0.05:


print("Today's afternoon was significantly different from the historical ave
rage.")
else:
print("Today's afternoon was within normal range.")

OUTPUT

Afternoon mean today: 25.8 C


p-value vs historical average: 0.0332
Today's afternoon was significantly different from the historical average.

What you just practiced


You filled in missing sensor data (interpolate), fit a physical model to noisy readings
(optimize.curve_fit), found an optimum point on that model (optimize.minimize_scalar), and ran a
real statistical test to check if a result was meaningful (stats.ttest_1samp). That is a genuine
end-to-end scientific computing workflow.

SciPy from Scratch — A Complete Beginner's Guide Page 20


PART 11

Practice Exercises
Test yourself — try to solve these before checking the solution

1. Find a root
Use [Link] to find the root of f(x) = x**3 - 2*x - 5 somewhere between 1 and 3.

Solution:

from scipy import optimize

def f(x):
return x**3 - 2*x - 5

root = [Link](f, 1, 3)
print(root) # 2.0945...

2. Integrate a curve
Compute the definite integral of f(x) = sin(x) from 0 to pi (the answer should be very close to 2).

Solution:

import numpy as np
from scipy import integrate

result, err = [Link]([Link], 0, [Link])


print(result) # 2.0 (approximately)

3. Fit a quadratic curve


Given noisy data that follows y = 2x^2 + 1, use curve_fit to recover the coefficients 2 and 1.

Solution:

SciPy from Scratch — A Complete Beginner's Guide Page 21


rng = [Link].default_rng(0)
x = [Link](-5, 5, 30)
y = 2 * x**2 + 1 + [Link](0, 2, size=30)

def quad_model(x, a, b):


return a * x**2 + b

params, _ = optimize.curve_fit(quad_model, x, y)
print(params) # close to [2, 1]

4. Compare two groups


Given two arrays of plant heights grown with different fertilizers, use a t-test to check if the difference is
statistically significant.

Solution:

from scipy import stats

fertilizer_a = [Link]([20, 22, 19, 24, 21])


fertilizer_b = [Link]([25, 27, 24, 28, 26])

t_stat, p_value = stats.ttest_ind(fertilizer_a, fertilizer_b)


print(p_value) # very small -> significant difference

SciPy from Scratch — A Complete Beginner's Guide Page 22


PART 12

Cheat Sheet
The most-used SciPy commands, all in one place

Task Code

Import a sub-package from scipy import optimize

Physical constants from scipy import constants

Find a root [Link](f, a, b)

Minimize a function [Link](f, x0)

Fit a curve to data optimize.curve_fit(model, x, y)

Definite integral [Link](f, a, b)

Solve a differential eqn integrate.solve_ivp(f, t_span, y0)

1D interpolation interpolate.make_interp_spline(x, y)

Solve linear system Ax=b [Link](A, b)

Determinant / inverse [Link](A) / [Link](A)

Eigenvalues [Link](A)

Create a distribution [Link](loc=mean, scale=std)

Descriptive stats [Link](data)

Two-sample t-test stats.ttest_ind(group1, group2)

One-sample t-test stats.ttest_1samp(data, expected)

Distance between points [Link](a, b)

Nearest-neighbor search [Link](points).query(p)

Smooth noisy data signal.savgol_filter(data, window, order)

Find peaks signal.find_peaks(data, height=h)

Where to go next
• Explore [Link] for image processing (blurring, edge detection, rotation).
• Explore [Link] if you ever work with huge matrices that are mostly zeros (common in graph
algorithms and recommendation systems).

SciPy from Scratch — A Complete Beginner's Guide Page 23


• Pair SciPy with matplotlib to visualize everything you compute — a fitted curve or a distribution is
much easier to understand as a picture.
• Read the official docs at [Link] — each sub-package's reference page includes worked examples
for nearly every function.
• Try re-doing the mini-project with a dataset of your own — stock prices, weather data, or anything
else you can find as a CSV.

You now know how to find roots and minima, integrate functions, interpolate missing data, solve linear
systems, work with probability distributions, run hypothesis tests, measure spatial distances, and filter
noisy signals — and you've used all of it together on a realistic sensor-data project. That is the real core of
SciPy.

SciPy from Scratch — A Complete Beginner's Guide Page 24

You might also like