Math 123: Mathematical Aspects of Data Analysis — Fall 2026
Published
August 8, 2026
Python for Data Analysis
This course is about the mathematical structure behind data analysis. We will explore that, computationally, with Python because it lets us move back and forth between that mathematics and concrete computations with very little friction. The notation in can be quite close to the linear algebra notation in the notes, the surrounding ecosystem is mature, and the same tools used for small classroom examples also scale to real data sets. While Python is not the point of the course, but it is an important working language for modern applied mathematics, statistics, and machine learning.
The links below are optional references. They are useful if you want a second explanation of Python syntax, a more systematic introduction to programming, or more background on the data-analysis libraries we will use.
Think Python is a gentler, more complete introduction to programming in Python.
A Whirlwind Tour of Python is a compact review of Python syntax and conventions, especially useful if you have programmed before but are new to Python.
Python for Data Analysis gives more depth on the data-analysis stack, especially NumPy and pandas.
Below is a brief taste of how use the language.
NumPy and SciPy: Why Not Plain Python?
Python’s built-in lists are flexible but slow for numerical work. A Python list is a collection of objects, each carrying type information, reference counts, and heap allocations. A loop over ten million numbers can mean ten million Python object touches, very slow.
NumPy solves this by storing data in contiguous blocks of memory (think a C array) and implements operations in compiled C/Fortran under the hood. It’s, therefore, far faster. Moreover, it has a syntax designed to make numerical, mathematical work easier. This is why the computational math ecosystem, in python, is largely standardized around libraries like NumPy.
import numpy as npfrom time import perf_countern =5_000_000# Python list versionpy_list =list(range(n))t0 = perf_counter()py_sum =sum(x**2for x in py_list)t_py = perf_counter() - t0# NumPy versionnp_arr = np.arange(n, dtype=np.float64)t0 = perf_counter()np_sum = np.dot(np_arr, np_arr)t_np = perf_counter() - t0print(f"Python list : {t_py:.3f} s")print(f"NumPy array : {t_np:.4f} s")print(f"Speedup : {t_py / t_np:.0f}×")
Python list : 0.233 s
NumPy array : 0.0021 s
Speedup : 113×
This is a ridiculous example, but it’s just to demonstrate the per-operation gains.
Likewise, as mentioned, NumPy also gives you the mental model that matches the math. Arrays are vectors and matrices, and the operations (@ for matrix multiplication, .T for transpose, np.linalg.* for decompositions) map directly onto the notation from math.
A = np.array([[1, 2], [3, 4], [5, 6]]) # 3×2 matrixv = np.array([1, -1]) # vector in R^2print("A @ v =", A @ v) # matrix-vector productprint("A.T shape:", A.T.shape) # transpose: 2×3
A @ v = [-1 -1 -1]
A.T shape: (2, 3)
SciPy sits on top of NumPy and provides higher-level scientific algorithms, e.g. sparse matrix formats, numerical integration, optimization, signal processing, and more. For this course the most relevant piece is scipy.linalg (which exposes LAPACK routines for decompositions not in NumPy). We may reach for SciPy when NumPy’s linalg module is not enough.
scikit-learn
scikit-learn is the standard Python library for classical machine learning. It provides:
A uniform estimator API: every model has .fit(X, y), .predict(X), and .score(X, y).
A large collection of algorithms (linear models, trees, SVMs, clustering, …).
The Iris dataset (Fisher, 1936) records four measurements, sepal length, sepal width, petal length, petal width, for 150 iris flowers spanning three species.