CrunchAcademy · K-12

Math for Data Science · MDS-1

Math Foundations for Data Science

Rebuild the core math that every data scientist secretly relies on, with Python alongside every concept.

MDS-1 rebuilds the mathematical vocabulary every data scientist depends on, from numerical precision to algebra, functions, logarithms, summation notation, logic, and a first look at vectors. Each unit pairs hand calculation with short Python snippets so the math and the code reinforce each other. By the end you will read formulas the way practitioners do and be ready for statistics, linear algebra, and calculus tracks.

PrereqsF-3 Math Foundations for Tech (or middle-school algebra)
Code inPython
7Units
48Lessons
144Worked examples

Course Outline

MDS-1 — units

Every lesson is self-contained: a full explanation, worked step-by-step examples (in Python), common mistakes, a try-it-yourself, and an interactive quiz. Jump to a unit:

Weeks 1-2 Unit 1: Numbers, Notation & Precision
Number systemsScientific notationSignificant figuresFloating-point precisionIntervals & inequalitiesDimensional reasoning
Lecture
Number systems: naturals, integers, rationals, reals

How mathematicians organize numbers into nested families, and why a data scientist cares which family a value lives in.

The number systems form nested sets. The naturals N = {1, 2, 3, ...} count things; the integers Z add zero and negatives; the rationals Q are all ratios a/b of integers with b not zero (their decimals terminate or repeat); and the reals R fill the line, adding irrationals like sqrt(2) and pi whose decimals never repeat. Each set contains the previous: N inside Z inside Q inside R. This matters in data science because a value's type drives its representation and its bugs: counts are integers (use exact arithmetic), proportions are rationals or reals (use floats), and irrational constants must be approximated. Knowing the family also tells you what operations are safe and where exactness is lost.

Worked Example 1

Problem. Classify each number into the smallest set it belongs to: 5, -3, 2/7, sqrt(2).

  1. 5 is a counting number, so it is a natural (and also integer, rational, real).
  2. -3 is negative, so it skips N but is an integer.
  3. 2/7 is a ratio of integers with nonzero denominator, so it is rational; its decimal 0.285714... repeats.
  4. sqrt(2) = 1.41421356... never terminates or repeats, so it is irrational, only a real.

Answer. 5: natural; -3: integer; 2/7: rational; sqrt(2): real (irrational).

Worked Example 2

Problem. Show that 0.75 is rational by writing it as a fraction of integers.

  1. 0.75 = 75/100 because there are two decimal places.
  2. Reduce by the common factor 25: 75/100 = 3/4.
  3. 3 and 4 are integers with 4 not zero, satisfying the definition of rational.

Answer. 0.75 = 3/4, a rational number.

Worked Example 3

Problem. Use Python to confirm 1/3 is stored as a repeating-style rational and that Fraction keeps it exact.

  1. from fractions import Fraction
  2. print(Fraction(1, 3)) # 1/3
  3. print(Fraction(1, 3) + Fraction(1, 6)) # 1/2
  4. print(float(Fraction(1, 3))) # 0.3333333333333333 (a real approximation)
  5. The Fraction type stays exact, while float() converts to an approximate real.

Answer. Fraction(1,3) + Fraction(1,6) = 1/2 exactly; the float is 0.3333333333333333.

Common mistakes
  • Thinking every decimal is irrational. Correct idea: terminating or repeating decimals (like 0.5 or 0.333...) are rational; only non-repeating, non-terminating decimals are irrational.
  • Calling 0 a natural number without checking the convention. Correct idea: many texts start N at 1; be explicit, and note 0 is always an integer.
  • Assuming integers and reals behave identically in code. Correct idea: integer division and float division differ, and floats lose exactness that integers keep.
✎ Try it yourself

Problem. Classify -8, 4.2, and pi, then write 4.2 as a fraction in lowest terms.

Solution. -8 is an integer (negative, so not natural). pi is irrational, hence real only. 4.2 = 42/10 = 21/5 after dividing by 2, so it is rational. Final: -8 integer, 4.2 rational (21/5), pi real/irrational.

Scientific notation and orders of magnitude

Writing very large or very small numbers compactly, and comparing their scale at a glance.

Scientific notation writes a value as m x 10^n where the mantissa satisfies 1 <= |m| < 10 and n is an integer exponent. A positive n shifts the decimal right (large numbers); a negative n shifts it left (small numbers). The order of magnitude is that exponent n, the nearest power of ten, which lets you compare scales instantly: 10^6 is a thousand times bigger than 10^3. Data scientists rely on this constantly to sanity-check results, report dataset sizes, express physical constants, and avoid overflow or underflow. It also underlies how floating-point numbers are stored internally, so fluency here makes precision issues easier to reason about.

Worked Example 1

Problem. Write 4{,}500{,}000 in scientific notation.

  1. Place the decimal after the first nonzero digit: 4.5.
  2. Count how many places the decimal moved: 4500000 -> 4.5 means 6 places left.
  3. Moving left gives a positive exponent: 10^6.

Answer. 4.5 x 10^6

Worked Example 2

Problem. Write 0.00067 in scientific notation and give its order of magnitude.

  1. First nonzero digit is 6, so mantissa is 6.7.
  2. 0.00067 -> 6.7 moves the decimal 4 places right, so the exponent is -4.
  3. Result: 6.7 x 10^-4; the order of magnitude is 10^-4.

Answer. 6.7 x 10^-4, order of magnitude 10^-4.

Worked Example 3

Problem. In Python, express 93{,}000{,}000 in scientific notation and read back its exponent.

  1. x = 93_000_000
  2. print(f'{x:.2e}') # 9.30e+07
  3. import math
  4. print(math.floor(math.log10(x))) # 7 (order of magnitude)

Answer. 9.30e+07, with order of magnitude 7.

Common mistakes
  • Leaving the mantissa outside 1 to 10, e.g. writing 42 x 10^5. Correct idea: normalize to 4.2 x 10^6 so 1 <= |m| < 10.
  • Getting the exponent sign backwards. Correct idea: small numbers (< 1) take negative exponents; large numbers take positive ones.
  • Confusing order of magnitude with the value. Correct idea: order of magnitude is just the power of ten (the exponent), not the whole number.
✎ Try it yourself

Problem. Write 0.0000031 in scientific notation and state how many orders of magnitude larger 3.1 x 10^2 is.

Solution. 0.0000031 = 3.1 x 10^-6 (decimal moves 6 places right). The exponents are -6 and 2, differing by 2 - (-6) = 8, so 3.1 x 10^2 is 8 orders of magnitude (10^8 times) larger.

Significant figures, rounding, and estimation

Tracking how much precision a number really carries and rounding without inventing accuracy.

Significant figures are the digits that carry meaningful precision: all nonzero digits count, zeros between them count, trailing zeros after a decimal point count, but leading zeros never do. Rounding keeps a chosen number of significant figures by looking at the next digit (5 or more rounds up). Estimation uses orders of magnitude to get a quick ballpark before computing exactly. In data science this prevents false precision: reporting a mean as 3.14159 when inputs were measured to two figures overstates certainty. It also drives sensible display formatting and helps you catch errors, since an estimate that is orders of magnitude off signals a bug.

Worked Example 1

Problem. How many significant figures are in 0.004070?

  1. Leading zeros (0.00) are not significant.
  2. The 4 is significant; the 0 between 4 and 7 is significant; the 7 is significant.
  3. The trailing 0 after the decimal is significant.
  4. Count: 4, 0, 7, 0 -> four significant figures.

Answer. 4 significant figures.

Worked Example 2

Problem. Round 2.4673 to 3 significant figures.

  1. The first three significant figures are 2, 4, 6.
  2. The next digit is 7, which is 5 or more, so round up.
  3. Rounding 2.46 up at the third figure gives 2.47.

Answer. 2.47

Worked Example 3

Problem. Round the mean of [12.1, 12.8, 13.0] to 3 significant figures in Python.

  1. import statistics
  2. m = statistics.mean([12.1, 12.8, 13.0]) # 12.633333...
  3. rounded = float(f'{m:.3g}')
  4. print(rounded) # 12.6

Answer. 12.6 (3 significant figures).

Common mistakes
  • Counting leading zeros as significant. Correct idea: 0.0052 has only two significant figures (5 and 2).
  • Reporting more figures than the data supports. Correct idea: a result is only as precise as its least precise input.
  • Rounding repeatedly in stages. Correct idea: round once at the end; chained rounding accumulates error.
✎ Try it yourself

Problem. State the significant figures in 1500.0 and round 0.08642 to 2 significant figures.

Solution. 1500.0 has 5 significant figures because the decimal point makes the trailing zeros meaningful. For 0.08642, the first two significant figures are 8 and 6; the next digit 4 is below 5, so it rounds down to 0.086.

Floating-point numbers and why 0.1 + 0.2 != 0.3

Understanding the binary approximation behind computer arithmetic and the tiny errors it creates.

Computers store most real numbers as floating-point: a sign, a binary mantissa, and a binary exponent (the IEEE 754 double format gives about 15-17 significant decimal digits). Many decimals that look simple, like 0.1, are infinitely repeating in binary, so they are stored as the nearest representable value, a hair off. Adding several such approximations lets the tiny errors surface, which is why 0.1 + 0.2 prints 0.30000000000000004. Machine epsilon is the gap between 1.0 and the next float. Data scientists must know this to compare floats with a tolerance instead of ==, to interpret near-zero residuals, and to avoid subtracting nearly equal large numbers, which magnifies error.

Worked Example 1

Problem. Predict and verify what 0.1 + 0.2 prints in Python.

  1. 0.1 and 0.2 cannot be stored exactly in binary, so each is rounded.
  2. Their stored values sum to slightly more than 0.3.
  3. print(0.1 + 0.2) # 0.30000000000000004
  4. print(0.1 + 0.2 == 0.3) # False

Answer. 0.30000000000000004, and the equality test is False.

Worked Example 2

Problem. Compare two floats safely using a tolerance.

  1. import math
  2. a, b = 0.1 + 0.2, 0.3
  3. print(math.isclose(a, b)) # True
  4. isclose uses a relative + absolute tolerance instead of exact equality.

Answer. math.isclose(0.1 + 0.2, 0.3) returns True.

Worked Example 3

Problem. Report machine epsilon and the exact stored value of 0.1.

  1. import sys
  2. print(sys.float_info.epsilon) # 2.220446049250313e-16
  3. from decimal import Decimal
  4. print(Decimal(0.1)) # 0.1000000000000000055511151231257827021181583404541015625

Answer. epsilon ~ 2.22e-16; 0.1 is actually stored as 0.10000000000000000555...

Common mistakes
  • Testing floats with ==. Correct idea: use math.isclose or compare abs(a - b) < tol.
  • Believing the error is a Python bug. Correct idea: it is inherent to IEEE 754 binary floating-point in nearly every language.
  • Assuming more decimals printed means more accuracy. Correct idea: a double carries only ~15-17 reliable significant digits.
✎ Try it yourself

Problem. Will 0.1 + 0.1 + 0.1 == 0.3 in Python? Explain and give a safe check.

Solution. It is False: each 0.1 is a rounded binary value, and three of them sum to 0.30000000000000004, not exactly 0.3. A safe test is math.isclose(0.1 + 0.1 + 0.1, 0.3), which returns True because it allows a small tolerance.

Absolute value, intervals, and inequalities on the number line

Measuring distance from zero and describing ranges of real numbers precisely.

The absolute value |x| is the distance of x from zero, so it is never negative: |5| = 5 and |-5| = 5. Inequalities like -2 <= x < 5 describe ranges on the number line, and interval notation records them compactly: a square bracket includes the endpoint, a parenthesis excludes it, and infinity always takes a parenthesis. Solving an absolute-value inequality such as |x - 3| < 2 means all points within distance 2 of 3, giving 1 < x < 5. These tools matter in data science for defining valid ranges, expressing error tolerances (|prediction - actual| < epsilon), filtering data, and stating the domains of functions clearly.

Worked Example 1

Problem. Write the set of all x with -2 <= x < 5 in interval notation.

  1. -2 is included, so use a square bracket [.
  2. 5 is excluded, so use a parenthesis ).
  3. Combine: [-2, 5).

Answer. [-2, 5)

Worked Example 2

Problem. Solve |x - 3| < 2 and write the solution as an interval.

  1. |x - 3| < 2 means -2 < x - 3 < 2.
  2. Add 3 to all parts: 1 < x < 5.
  3. Both endpoints excluded, so the interval is (1, 5).

Answer. (1, 5)

Worked Example 3

Problem. Use Python to keep only data values within distance 2 of the target 3.

  1. data = [0, 1.5, 3, 4.9, 6]
  2. kept = [x for x in data if abs(x - 3) < 2]
  3. print(kept) # [1.5, 3, 4.9]

Answer. [1.5, 3, 4.9] are the values satisfying |x - 3| < 2.

Common mistakes
  • Writing |x| = -x is always wrong. Correct idea: |x| = -x only when x is negative; the result is still non-negative.
  • Including infinity with a bracket, like [3, inf]. Correct idea: infinity is not a number, so it always takes a parenthesis: [3, inf).
  • Solving |x| > 3 as a single interval. Correct idea: it splits into x < -3 or x > 3, a union of two intervals.
✎ Try it yourself

Problem. Solve |2x| <= 6 and express the answer in interval notation.

Solution. |2x| <= 6 means -6 <= 2x <= 6. Divide all parts by 2: -3 <= x <= 3. Both endpoints are included, so the interval is [-3, 3].

Units, dimensional reasoning, and sanity checks

Tracking units through a calculation so the answer's dimensions confirm it is plausible.

Dimensional reasoning treats units (meters, seconds, dollars) as algebraic factors that multiply, divide, and cancel just like variables. A correct formula must have matching units on both sides: speed = distance / time yields meters/second, and you cannot add quantities with different dimensions. Carrying units through a computation is a powerful sanity check, if the final unit is wrong, the formula is wrong, no matter how clean the arithmetic looks. In data science this catches errors in feature engineering and rate calculations, validates unit conversions, and supports quick order-of-magnitude estimates so you can tell whether a result like 'average session = 4000 seconds' is reasonable.

Worked Example 1

Problem. A car travels 150 km in 2 hours. Find its average speed and confirm the units.

  1. Speed = distance / time = 150 km / 2 h.
  2. Divide the numbers: 75; divide the units: km/h.
  3. Units km/h are a valid speed unit, confirming the formula.

Answer. 75 km/h

Worked Example 2

Problem. Convert 75 km/h to meters per second using unit cancellation.

  1. 75 km/h x (1000 m / 1 km) cancels km, giving 75000 m/h.
  2. x (1 h / 3600 s) cancels h, giving 75000 / 3600 m/s.
  3. 75000 / 3600 = 20.833... m/s.

Answer. About 20.83 m/s

Worked Example 3

Problem. In Python, convert 75 km/h to m/s with explicit conversion factors.

  1. km_per_h = 75
  2. m_per_s = km_per_h * 1000 / 3600
  3. print(round(m_per_s, 2)) # 20.83

Answer. 20.83 m/s

Common mistakes
  • Adding quantities with different units, like meters + seconds. Correct idea: only like-dimensioned quantities can be added; convert first.
  • Forgetting to invert a conversion factor. Correct idea: arrange each factor so the unwanted unit cancels (appears once on top, once on bottom).
  • Ignoring the units of the final answer. Correct idea: always check the resulting unit; a wrong unit reveals a wrong formula.
✎ Try it yourself

Problem. A pump moves 240 liters in 4 minutes. Find the flow rate in liters per second and check the unit.

Solution. Rate = 240 L / 4 min = 60 L/min. Convert: 60 L/min x (1 min / 60 s) = 1 L/s. The minutes cancel, leaving liters per second, a valid flow-rate unit, so the answer is 1 L/s.

Key terms
  • Rational number — a number expressible as a ratio of two integers a/b with b not zero.
  • Scientific notation — writing a value as m x 10^n with 1 <= |m| < 10.
  • Significant figures — the digits in a measurement that carry meaningful precision.
  • Floating-point — a finite binary approximation of real numbers used by computers.
  • Machine epsilon — the smallest gap between 1.0 and the next representable float.
  • Absolute value — the distance of a number from zero, written |x|.
  • Interval notation — a compact way to write a range, e.g. [0, 1) or (-inf, 5].
  • Order of magnitude — the power of ten nearest a value, used for quick estimation.
Assignment · Precision Detective

Pick three real-world quantities (e.g. the world population, the mass of an electron, your screen's pixel count) and write each in scientific notation with the correct number of significant figures. Then in Python, compute 0.1 + 0.2 and print it, and use sys.float_info.epsilon to report machine epsilon. Explain in two sentences why the sum is not exactly 0.3.

Deliverable · A short notebook or script with the three values, the float demonstration, and a written explanation of the rounding error.

Quiz · 5 questions
  1. 1. Which set does the number -7 belong to but 3.5 does not?

  2. 2. Express 0.00042 in scientific notation.

  3. 3. Why does 0.1 + 0.2 not equal exactly 0.3 in most languages?

  4. 4. Which interval describes all x with -2 <= x < 5?

  5. 5. How many significant figures are in 0.003080?

You'll be able to

I can classify numbers and express very large or small values in scientific notation.

I can explain why floating-point arithmetic introduces rounding error and predict where it bites.

I can use interval notation to describe sets of real numbers.

Weeks 3-4 Unit 2: Algebra Essentials
Order of operationsLinear equationsExponent rulesFactoring polynomialsRational expressionsSystems of equationsAlgebraic modeling
Lecture
Variables, expressions, and the order of operations

How algebra uses symbols to stand for numbers, and the fixed precedence rules that make an expression mean one thing.

A variable is a symbol holding an unknown or changing value; an expression combines variables, numbers, and operations but has no equals sign. To evaluate an expression unambiguously, everyone follows the same order of operations, often remembered as PEMDAS: Parentheses, Exponents, Multiplication and Division (left to right), then Addition and Subtraction (left to right). Without this convention 3 + 4 * 2 could mean 14 or 11; the rule fixes it at 11. This matters in data science because formulas, spreadsheet cells, and code all assume the same precedence: a misplaced parenthesis silently changes a feature calculation or a loss function. Reading expressions correctly is the foundation for every later manipulation.

Worked Example 1

Problem. Evaluate 3 + 4 * 2^2.

  1. Exponent first: 2^2 = 4.
  2. Multiplication next: 4 * 4 = 16.
  3. Addition last: 3 + 16 = 19.

Answer. 19

Worked Example 2

Problem. Evaluate (6 - 2) * 3 + 8 / 4.

  1. Parentheses first: 6 - 2 = 4.
  2. Multiply and divide left to right: 4 * 3 = 12 and 8 / 4 = 2.
  3. Add: 12 + 2 = 14.

Answer. 14

Worked Example 3

Problem. Confirm operator precedence in Python for 3 + 4 * 2 ** 2.

  1. print(3 + 4 * 2 ** 2) # 19
  2. Python uses the same precedence: ** before *, * before +.
  3. print((3 + 4) * 2 ** 2) # 28 (parentheses change the result)

Answer. 3 + 4 * 2 ** 2 gives 19; adding parentheses gives 28.

Common mistakes
  • Working strictly left to right. Correct idea: multiplication and exponents bind tighter than addition regardless of position.
  • Treating multiplication as always before division. Correct idea: they share a level and are done left to right.
  • Forgetting that -3^2 means -(3^2) = -9, not 9. Correct idea: the exponent binds tighter than the unary minus.
✎ Try it yourself

Problem. Evaluate 10 - 2 * 3 + 4^2 / 8.

Solution. Exponent: 4^2 = 16. Multiply/divide left to right: 2 * 3 = 6 and 16 / 8 = 2. Now 10 - 6 + 2, left to right: 10 - 6 = 4, 4 + 2 = 6. Final answer: 6.

Solving linear equations and inequalities

Isolating a variable using inverse operations, and the one rule that changes when inequalities are involved.

A linear equation has the variable only to the first power, like 5 - 2x = 11. You solve it by applying inverse operations to both sides until the variable is alone, keeping the equation balanced at every step. Inequalities (<, >, <=, >=) are solved the same way with one crucial exception: multiplying or dividing both sides by a negative number flips the inequality direction. The solution to an equation is usually a single value; the solution to an inequality is a range. Data scientists solve these constantly when inverting formulas, finding thresholds, setting decision boundaries, and expressing constraints, so fluency with the balance principle is essential.

Worked Example 1

Problem. Solve 5 - 2x = 11.

  1. Subtract 5 from both sides: -2x = 6.
  2. Divide both sides by -2: x = -3.
  3. Check: 5 - 2(-3) = 5 + 6 = 11. Correct.

Answer. x = -3

Worked Example 2

Problem. Solve the inequality -3x + 1 < 10.

  1. Subtract 1: -3x < 9.
  2. Divide by -3 and flip the sign: x > -3.
  3. Solution is all x greater than -3, interval (-3, inf).

Answer. x > -3

Worked Example 3

Problem. Solve 4(x - 2) = 2x + 6 and verify in Python with sympy.

  1. Expand: 4x - 8 = 2x + 6.
  2. Subtract 2x: 2x - 8 = 6; add 8: 2x = 14; divide: x = 7.
  3. import sympy as sp; x = sp.symbols('x')
  4. print(sp.solve(sp.Eq(4*(x-2), 2*x+6), x)) # [7]

Answer. x = 7

Common mistakes
  • Forgetting to flip the inequality when dividing by a negative. Correct idea: -2x < 6 becomes x > -3, not x < -3.
  • Applying an operation to only one side. Correct idea: whatever you do to one side you must do to the other to stay balanced.
  • Distributing incorrectly, e.g. 4(x - 2) = 4x - 2. Correct idea: multiply every term inside, giving 4x - 8.
✎ Try it yourself

Problem. Solve 7 - 3x >= 1 and write the solution as an interval.

Solution. Subtract 7: -3x >= -6. Divide by -3 and flip: x <= 2. As an interval, (-inf, 2].

Exponent rules and radicals

The identities for combining powers and the link between roots and fractional exponents.

Exponent rules let you combine powers without expanding them: a^m * a^n = a^(m+n), a^m / a^n = a^(m-n), (a^m)^n = a^(mn), a^0 = 1, and a^(-n) = 1/a^n. Radicals are exponents in disguise: the square root of a equals a^(1/2), and the n-th root equals a^(1/n), so a^(m/n) is the n-th root of a^m. These rules power everything from simplifying model expressions to understanding how variance (a squared quantity) relates to standard deviation (its square root). Mastering them lets you rewrite messy expressions into forms that are easier to differentiate, factor, or compute.

Worked Example 1

Problem. Simplify x^5 / x^2.

  1. Dividing like bases subtracts exponents: 5 - 2 = 3.
  2. Result is x^3.

Answer. x^3

Worked Example 2

Problem. Simplify (2x^3)^2 * x.

  1. Apply the power-of-a-product rule: (2x^3)^2 = 2^2 * x^(3*2) = 4x^6.
  2. Multiply by x: 4x^6 * x = 4x^(6+1) = 4x^7.

Answer. 4x^7

Worked Example 3

Problem. Rewrite the cube root of x^6 as a power and evaluate at x = 2 in Python.

  1. The cube root is exponent 1/3: (x^6)^(1/3) = x^(6/3) = x^2.
  2. x = 2; print(x**2) # 4
  3. print((2**6) ** (1/3)) # 3.9999999999999996 (float approximation of 4)

Answer. x^2, which is 4 at x = 2; the float root prints ~4.0.

Common mistakes
  • Writing a^m * a^n = a^(m*n). Correct idea: multiplying like bases adds exponents, giving a^(m+n).
  • Thinking a^0 = 0. Correct idea: any nonzero base to the zero power is 1.
  • Treating (a + b)^2 as a^2 + b^2. Correct idea: it expands to a^2 + 2ab + b^2; powers do not distribute over addition.
✎ Try it yourself

Problem. Simplify (3x^2 y)^2 / (9x y^2).

Solution. Numerator: (3x^2 y)^2 = 9 x^4 y^2. Divide by 9 x y^2: (9/9) x^(4-1) y^(2-2) = x^3 y^0 = x^3. Final answer: x^3.

Factoring and expanding polynomials

Moving between a product of factors and an expanded sum, the two-way street at the heart of algebra.

Expanding multiplies out a product into a sum of terms using the distributive law, e.g. (x + 3)(x - 3) = x^2 - 9. Factoring reverses this, rewriting a sum as a product, which exposes roots and common structure. Key patterns include the greatest common factor, the difference of squares a^2 - b^2 = (a + b)(a - b), and trinomials x^2 + bx + c = (x + p)(x + q) where p + q = b and pq = c. In data science, factoring reveals where a function equals zero (its roots), simplifies expressions before computation, and underlies polynomial regression and characteristic equations in linear algebra.

Worked Example 1

Problem. Factor x^2 - 9.

  1. Recognize a difference of squares: x^2 - 3^2.
  2. Apply a^2 - b^2 = (a + b)(a - b) with a = x, b = 3.

Answer. (x + 3)(x - 3)

Worked Example 2

Problem. Factor x^2 + 5x + 6.

  1. Find two numbers multiplying to 6 and adding to 5: 2 and 3.
  2. Write as (x + 2)(x + 3).
  3. Check by expanding: x^2 + 3x + 2x + 6 = x^2 + 5x + 6.

Answer. (x + 2)(x + 3)

Worked Example 3

Problem. Factor 2x^2 - 8x and verify with sympy in Python.

  1. Pull out the common factor 2x: 2x(x - 4).
  2. import sympy as sp; x = sp.symbols('x')
  3. print(sp.factor(2*x**2 - 8*x)) # 2*x*(x - 4)

Answer. 2x(x - 4)

Common mistakes
  • Forgetting the greatest common factor first. Correct idea: always pull out shared factors before trying patterns.
  • Misidentifying signs in a trinomial. Correct idea: the constant's sign tells you whether the two numbers share or differ in sign.
  • Treating x^2 + 9 as factorable over the reals. Correct idea: a sum of squares does not factor with real coefficients.
✎ Try it yourself

Problem. Factor x^2 - x - 12 completely.

Solution. Find two numbers multiplying to -12 and adding to -1: they are -4 and 3. So x^2 - x - 12 = (x - 4)(x + 3). Check: x^2 + 3x - 4x - 12 = x^2 - x - 12.

Rational expressions and simplification

Fractions whose numerator and denominator are polynomials, and how to reduce and combine them safely.

A rational expression is a ratio of two polynomials, like (x^2 - 9)/(x + 3). You simplify it by factoring top and bottom, then cancelling common factors, but only factors, never individual terms. Crucially, any input that makes the original denominator zero is excluded from the domain even after cancellation, because the simplified form must describe the same function. Adding or subtracting rational expressions requires a common denominator, just like numeric fractions. These show up in data science within rate formulas, normalized scores, probability ratios, and the algebra of model expressions, where careless cancellation introduces subtle errors.

Worked Example 1

Problem. Simplify (x^2 - 9)/(x + 3).

  1. Factor the numerator: x^2 - 9 = (x + 3)(x - 3).
  2. Cancel the common factor (x + 3): leaves x - 3.
  3. Note the restriction x != -3 from the original denominator.

Answer. x - 3, with x != -3

Worked Example 2

Problem. Add 1/x + 2/(x + 1) as a single fraction.

  1. Common denominator is x(x + 1).
  2. Rewrite: (x + 1)/(x(x+1)) + 2x/(x(x+1)).
  3. Combine numerators: (x + 1 + 2x)/(x(x+1)) = (3x + 1)/(x(x+1)).

Answer. (3x + 1)/(x(x + 1))

Worked Example 3

Problem. Simplify (x^2 - 4)/(x^2 + 4x + 4) with sympy.

  1. import sympy as sp; x = sp.symbols('x')
  2. print(sp.simplify((x**2 - 4)/(x**2 + 4*x + 4))) # (x - 2)/(x + 2)
  3. By hand: (x-2)(x+2) over (x+2)^2 cancels one (x+2).

Answer. (x - 2)/(x + 2), with x != -2

Common mistakes
  • Cancelling terms instead of factors, e.g. (x + 3)/3 = x. Correct idea: you may only cancel a factor common to the entire numerator and denominator.
  • Forgetting domain restrictions after cancelling. Correct idea: excluded values from the original denominator still apply.
  • Adding fractions by adding numerators and denominators. Correct idea: convert to a common denominator first.
✎ Try it yourself

Problem. Simplify (x^2 + 6x + 9)/(x^2 - 9) and state the restriction.

Solution. Factor: numerator (x + 3)^2, denominator (x + 3)(x - 3). Cancel one (x + 3): (x + 3)/(x - 3). Restrictions x != 3 and x != -3 from the original denominator.

Systems of linear equations

Solving for values that satisfy several linear equations at once, by hand and with NumPy.

A system of linear equations is two or more equations sharing the same variables; a solution makes every equation true simultaneously. Two common hand methods are substitution (solve one equation for a variable and plug into the other) and elimination (add or subtract scaled equations to cancel a variable). Geometrically, two equations in two unknowns are lines, and the solution is their intersection point. Systems are the backbone of linear algebra and underlie regression, where fitting parameters means solving a system. In Python, numpy.linalg.solve handles the matrix form Ax = b efficiently, which is exactly how practitioners solve large systems.

Worked Example 1

Problem. Solve 2x + 3y = 12 and x - y = 1 by substitution.

  1. From the second equation, x = y + 1.
  2. Substitute: 2(y + 1) + 3y = 12 -> 2y + 2 + 3y = 12 -> 5y = 10 -> y = 2.
  3. Back-substitute: x = 2 + 1 = 3.

Answer. x = 3, y = 2

Worked Example 2

Problem. Solve x + y = 5 and 2x - y = 1 by elimination.

  1. Add the two equations to cancel y: (x + 2x) + (y - y) = 5 + 1 -> 3x = 6 -> x = 2.
  2. Substitute x = 2 into x + y = 5: y = 3.

Answer. x = 2, y = 3

Worked Example 3

Problem. Solve the first system again with numpy.linalg.solve.

  1. import numpy as np
  2. A = np.array([[2, 3], [1, -1]]); b = np.array([12, 1])
  3. print(np.linalg.solve(A, b)) # [3. 2.]

Answer. [3., 2.], matching x = 3, y = 2.

Common mistakes
  • Substituting into the same equation you solved. Correct idea: plug the expression into the other equation to actually reduce the unknowns.
  • Sign errors during elimination. Correct idea: line up terms and track signs carefully when adding or subtracting equations.
  • Assuming every system has one solution. Correct idea: parallel lines give no solution, identical lines give infinitely many.
✎ Try it yourself

Problem. Solve 3x + y = 9 and x - 2y = -4.

Solution. From the first equation, y = 9 - 3x. Substitute into the second: x - 2(9 - 3x) = -4 -> x - 18 + 6x = -4 -> 7x = 14 -> x = 2. Then y = 9 - 6 = 3. Solution: x = 2, y = 3.

Word problems: translating language into algebra

Turning a sentence describing a situation into an equation you can solve.

Modeling a word problem means assigning variables to unknown quantities, then translating the relationships in the text into equations. Keywords map to operations: 'sum' or 'total' means addition, 'per' or 'each' signals multiplication or a rate, 'is' becomes the equals sign, and 'less than' often reverses order. After defining variables clearly, write equations that capture every stated condition, solve, and then check the answer back against the original wording for plausibility (right units, sensible magnitude). This skill is central to data science, where you constantly translate business questions, metrics, and constraints into formulas and code before any computation happens.

Worked Example 1

Problem. A number plus twice another is 14, and the two numbers differ by 2. Find them.

  1. Let the numbers be a and b: a + 2b = 14 and a - b = 2.
  2. From the second, a = b + 2; substitute: (b + 2) + 2b = 14 -> 3b = 12 -> b = 4.
  3. Then a = 4 + 2 = 6.

Answer. The numbers are 6 and 4.

Worked Example 2

Problem. A subscription costs a 10 dollar fee plus 5 dollars per month. After how many months does the total reach 60 dollars?

  1. Let m be months: total = 10 + 5m.
  2. Set equal to 60: 10 + 5m = 60.
  3. Subtract 10: 5m = 50; divide: m = 10.

Answer. 10 months

Worked Example 3

Problem. Two products sell for 3 and 5 dollars; 20 items sold for 76 dollars total. How many of each? Verify in Python.

  1. Let x be the 3-dollar items: x + y = 20 and 3x + 5y = 76.
  2. Substitute y = 20 - x: 3x + 5(20 - x) = 76 -> 3x + 100 - 5x = 76 -> -2x = -24 -> x = 12, y = 8.
  3. import numpy as np; print(np.linalg.solve([[1,1],[3,5]], [20,76])) # [12. 8.]

Answer. 12 of the 3-dollar item and 8 of the 5-dollar item.

Common mistakes
  • Defining variables vaguely. Correct idea: write exactly what each variable represents, including units, before forming equations.
  • Misreading 'less than', e.g. '5 less than x' as 5 - x. Correct idea: it means x - 5.
  • Skipping the final sanity check. Correct idea: substitute the answer back into the original wording to confirm it makes sense.
✎ Try it yourself

Problem. Tickets cost 8 dollars for adults and 5 dollars for children. 30 tickets sold for 192 dollars. How many adult tickets?

Solution. Let a be adults, c children: a + c = 30 and 8a + 5c = 192. Substitute c = 30 - a: 8a + 5(30 - a) = 192 -> 8a + 150 - 5a = 192 -> 3a = 42 -> a = 14. So 14 adult tickets (and 16 child).

Key terms
  • Variable — a symbol standing for an unknown or changing quantity.
  • Coefficient — the numeric multiplier of a variable term.
  • Linear equation — an equation whose variables appear only to the first power.
  • Exponent rule — identities such as a^m * a^n = a^(m+n).
  • Factoring — rewriting an expression as a product of simpler factors.
  • System of equations — two or more equations sharing the same variables.
  • Substitution — replacing a variable with an equivalent expression to solve.
  • Inequality — a statement comparing two expressions with <, >, <=, or >=.
Assignment · Solve It Two Ways

Hand-solve the system 2x + 3y = 12 and x - y = 1 using substitution, showing every step. Then verify your answer in Python using numpy.linalg.solve with the coefficient matrix and constant vector. Confirm both methods agree and note any tiny floating-point difference.

Deliverable · Worked-by-hand solution plus a Python snippet whose printed result matches your manual answer.

Quiz · 5 questions
  1. 1. Evaluate 3 + 4 * 2^2 using the order of operations.

  2. 2. Simplify x^5 / x^2.

  3. 3. Factor x^2 - 9.

  4. 4. Solve 5 - 2x = 11 for x.

  5. 5. When you multiply both sides of an inequality by a negative number, you must:

You'll be able to

I can manipulate algebraic expressions using exponent and factoring rules.

I can solve linear equations, inequalities, and small systems by hand.

I can translate a word problem into an equation and solve it.

Weeks 5-6 Unit 3: Functions & Graphs
Function notationSlope & interceptsQuadraticsPiecewise functionsTransformationsComposition & inversesPlotting
Lecture
Function notation, domain, and range

Reading the f(x) shorthand and pinning down which inputs are allowed and which outputs appear.

A function is a rule that assigns exactly one output to each input. Function notation f(x) names the rule f and the input x, so f(3) means evaluate the rule at 3. The domain is the set of allowed inputs; it shrinks wherever an operation breaks, such as dividing by zero or taking an even root of a negative. The range is the set of outputs the rule actually produces. In data science a function models how a feature maps to a prediction, and knowing the domain prevents runtime errors (a log of zero, a negative under a square root), while the range tells you the plausible spread of outputs. Reading f(x) fluently is the gateway to every formula you will meet later.

Worked Example 1

Problem. For f(x) = 2x + 1, compute f(0), f(3), and f(-2).

  1. f(0) = 2(0) + 1 = 1.
  2. f(3) = 2(3) + 1 = 7.
  3. f(-2) = 2(-2) + 1 = -3.

Answer. f(0) = 1, f(3) = 7, f(-2) = -3.

Worked Example 2

Problem. Find the domain of f(x) = 1 / (x - 2) and of g(x) = sqrt(x - 5).

  1. For f, the denominator x - 2 must not be zero, so x != 2.
  2. Domain of f is all reals except 2.
  3. For g, the radicand x - 5 must be >= 0, so x >= 5.
  4. Domain of g is [5, inf).

Answer. Domain f: all reals except 2; domain g: x >= 5, i.e. [5, inf).

Worked Example 3

Problem. Define f(x) = x^2 - 4 in Python and evaluate it, then describe its range.

  1. def f(x): return x**2 - 4
  2. print(f(0), f(2), f(-3)) # -4 0 5
  3. Since x^2 >= 0, the smallest output is at x = 0, giving -4.
  4. Range is all values >= -4, i.e. [-4, inf).

Answer. f(0) = -4, f(2) = 0, f(-3) = 5; range is [-4, inf).

Common mistakes
  • Reading f(x) as f times x. Correct idea: f(x) means 'apply rule f to input x', not multiplication.
  • Forgetting to exclude inputs that break the rule. Correct idea: remove values causing division by zero or even roots of negatives from the domain.
  • Confusing domain and range. Correct idea: domain is the allowed inputs (x), range is the produced outputs (y).
✎ Try it yourself

Problem. For h(x) = sqrt(x) / (x - 9), state the domain.

Solution. The square root requires x >= 0, and the denominator requires x != 9. Combining: x >= 0 and x != 9, i.e. [0, 9) union (9, inf).

Linear functions, slope, and intercepts

The straight-line model y = mx + b and what its two parameters mean.

A linear function has the form f(x) = mx + b, graphing as a straight line. The slope m is the rate of change, rise over run, computed from two points as (y2 - y1)/(x2 - x1); it tells you how much the output moves per unit of input. The y-intercept b is the output when x = 0, where the line crosses the vertical axis. Linear functions are the heartbeat of data science: linear regression fits exactly this form, where the slope is a learned weight and the intercept is a bias term. Reading slope and intercept off a line, or building the equation from a point and a slope, is a daily skill once you start modeling relationships in data.

Worked Example 1

Problem. Find the slope of the line through (1, 2) and (4, 11).

  1. slope = (y2 - y1)/(x2 - x1) = (11 - 2)/(4 - 1).
  2. = 9 / 3 = 3.

Answer. slope = 3

Worked Example 2

Problem. Write the equation of the line with slope 2 passing through (0, 3).

  1. The point (0, 3) gives the y-intercept directly: b = 3.
  2. Use y = mx + b with m = 2 and b = 3.
  3. Equation: y = 2x + 3.

Answer. y = 2x + 3

Worked Example 3

Problem. Fit a line through (0, 1) and (2, 5) in Python using numpy.polyfit.

  1. import numpy as np
  2. x = np.array([0, 2]); y = np.array([1, 5])
  3. m, b = np.polyfit(x, y, 1)
  4. print(m, b) # 2.0 1.0

Answer. slope m = 2, intercept b = 1, so y = 2x + 1.

Common mistakes
  • Inverting the slope formula as (x2 - x1)/(y2 - y1). Correct idea: slope is change in y over change in x.
  • Confusing the slope with the intercept. Correct idea: m scales x, b is the standalone constant where x = 0.
  • Assuming a vertical line has a slope. Correct idea: a vertical line has undefined slope because run is zero.
✎ Try it yourself

Problem. Find the equation of the line through (2, 1) and (6, 9).

Solution. Slope = (9 - 1)/(6 - 2) = 8/4 = 2. Use point (2, 1): y - 1 = 2(x - 2) -> y = 2x - 4 + 1 = 2x - 3. Equation: y = 2x - 3.

Quadratic functions and parabolas

The U-shaped curve f(x) = ax^2 + bx + c and how to locate its turning point.

A quadratic function f(x) = ax^2 + bx + c graphs as a parabola, opening upward when a > 0 and downward when a < 0. Its turning point, the vertex, sits at x = -b/(2a); plugging that back in gives the vertex's y-value, the function's minimum or maximum. The roots, where f(x) = 0, come from factoring or the quadratic formula x = (-b ± sqrt(b^2 - 4ac))/(2a). Quadratics appear throughout data science: squared error loss is a parabola in each parameter, so minimizing it means finding a vertex, and many optimization problems reduce to locating the bottom of a quadratic bowl. Recognizing the vertex and roots lets you reason about where a model is best.

Worked Example 1

Problem. Find the vertex of f(x) = x^2 - 4x + 1.

  1. Here a = 1, b = -4, so the vertex x-value is -b/(2a) = 4/2 = 2.
  2. Evaluate: f(2) = 4 - 8 + 1 = -3.
  3. Vertex is at (2, -3).

Answer. Vertex (2, -3), a minimum since a > 0.

Worked Example 2

Problem. Find the roots of x^2 - 5x + 6 = 0.

  1. Factor: two numbers multiplying to 6 and adding to -5 are -2 and -3.
  2. (x - 2)(x - 3) = 0.
  3. Set each factor to zero: x = 2 or x = 3.

Answer. x = 2 and x = 3.

Worked Example 3

Problem. Find the roots of 2x^2 + 3x - 2 = 0 in Python with numpy.roots.

  1. import numpy as np
  2. print(np.roots([2, 3, -2])) # [-2. 0.5]
  3. Check by the formula: (-3 ± sqrt(9 + 16))/4 = (-3 ± 5)/4 = 0.5 or -2.

Answer. x = -2 and x = 0.5.

Common mistakes
  • Using x = b/(2a) without the negative sign. Correct idea: the vertex is at x = -b/(2a).
  • Forgetting a quadratic can have zero, one, or two real roots. Correct idea: the discriminant b^2 - 4ac decides how many.
  • Assuming the parabola always opens upward. Correct idea: it opens downward when a is negative.
✎ Try it yourself

Problem. Find the vertex and roots of f(x) = x^2 - 6x + 8.

Solution. Vertex x = -(-6)/(2*1) = 3, f(3) = 9 - 18 + 8 = -1, so vertex (3, -1). Roots: factor (x - 2)(x - 4) = 0, giving x = 2 and x = 4.

Piecewise and absolute-value functions

Functions defined by different rules on different intervals, including the V-shaped absolute value.

A piecewise function uses different formulas on different parts of its domain, with each piece labeled by a condition on x. The absolute-value function f(x) = |x| is the classic example: it equals x when x >= 0 and -x when x < 0, producing a V shape with its corner at the origin. Evaluating a piecewise function means first checking which condition the input satisfies, then applying that piece. In data science, piecewise rules appear everywhere: the ReLU activation max(0, x) is piecewise, absolute error |prediction - actual| measures deviation, and tiered pricing or thresholds are naturally piecewise. Handling the branch conditions correctly is essential to avoid evaluating the wrong rule.

Worked Example 1

Problem. Given f(x) = x + 1 for x < 0 and f(x) = x^2 for x >= 0, find f(-3) and f(2).

  1. f(-3): since -3 < 0, use x + 1 = -3 + 1 = -2.
  2. f(2): since 2 >= 0, use x^2 = 4.

Answer. f(-3) = -2 and f(2) = 4.

Worked Example 2

Problem. Evaluate g(x) = |x - 3| at x = 1 and x = 7.

  1. g(1) = |1 - 3| = |-2| = 2.
  2. g(7) = |7 - 3| = |4| = 4.
  3. The corner (minimum) of g is at x = 3, where g = 0.

Answer. g(1) = 2 and g(7) = 4.

Worked Example 3

Problem. Implement the ReLU function max(0, x) in Python and test it.

  1. def relu(x): return x if x >= 0 else 0
  2. print(relu(-5), relu(0), relu(3)) # 0 0 3
  3. ReLU is piecewise: 0 for negative inputs, x for non-negative inputs.

Answer. relu(-5) = 0, relu(0) = 0, relu(3) = 3.

Common mistakes
  • Applying the wrong piece by mis-checking the condition. Correct idea: always test which interval the input falls in first.
  • Thinking |x| can be negative. Correct idea: absolute value is never negative; it outputs distance from zero.
  • Treating |x - 3| as |x| - 3. Correct idea: evaluate inside the bars first, then take absolute value.
✎ Try it yourself

Problem. For f(x) = -x for x < 1 and f(x) = 2x for x >= 1, find f(-2) and f(4).

Solution. f(-2): -2 < 1, so use -x = -(-2) = 2. f(4): 4 >= 1, so use 2x = 8. Final: f(-2) = 2, f(4) = 8.

Transformations: shifts, stretches, and reflections

How small changes to a function's formula move, scale, or flip its graph.

Starting from a base function f(x), predictable edits transform its graph. Adding outside, f(x) + k, shifts it up by k; subtracting shifts down. Changing the input, f(x - h), shifts right by h (note the counterintuitive sign). Multiplying outside, a*f(x), stretches vertically by factor a, and a negative a reflects across the x-axis. Multiplying the input, f(bx), compresses horizontally. Combined as a*f(x - h) + k, these describe almost any transformed graph. In data science, transformations correspond to scaling and centering features, shifting baselines, and flipping signs in loss functions, so recognizing how a formula edit reshapes a curve helps you reason about preprocessing and model behavior visually.

Worked Example 1

Problem. Describe how g(x) = (x - 2)^2 + 3 transforms the base f(x) = x^2.

  1. The (x - 2) inside shifts the parabola right by 2.
  2. The + 3 outside shifts it up by 3.
  3. Vertex moves from (0, 0) to (2, 3).

Answer. Right 2 and up 3; new vertex (2, 3).

Worked Example 2

Problem. Describe g(x) = -2 x^2 relative to f(x) = x^2.

  1. The factor 2 stretches the parabola vertically (steeper).
  2. The negative sign reflects it across the x-axis (opens downward).
  3. So it is a downward parabola, twice as steep.

Answer. Vertical stretch by 2 and reflection over the x-axis (opens down).

Worked Example 3

Problem. Plot f(x) = x^2 and g(x) = (x - 1)^2 - 2 in Python to confirm the shift.

  1. import numpy as np, matplotlib.pyplot as plt
  2. x = np.linspace(-3, 4, 100)
  3. plt.plot(x, x**2); plt.plot(x, (x - 1)**2 - 2); plt.show()
  4. The second curve's vertex sits at (1, -2), confirming right 1 and down 2.

Answer. g is f shifted right 1 and down 2, with vertex (1, -2).

Common mistakes
  • Reading f(x - h) as a left shift. Correct idea: subtracting inside shifts right by h; adding inside shifts left.
  • Confusing vertical and horizontal scaling. Correct idea: a factor outside (a*f(x)) stretches vertically; a factor inside (f(bx)) affects the horizontal.
  • Missing that a negative outside flips over the x-axis while a negative inside flips over the y-axis.
✎ Try it yourself

Problem. Describe how g(x) = -(x + 3)^2 + 1 transforms f(x) = x^2 and give the vertex.

Solution. The (x + 3) shifts left 3, the leading minus reflects over the x-axis (opens down), and + 1 shifts up 1. Vertex moves to (-3, 1).

Composition and inverse functions

Chaining functions together and building the rule that undoes a function.

Composition applies one function to the output of another: (f o g)(x) = f(g(x)), so you evaluate g first, then feed its result into f. Order matters; f o g usually differs from g o f. An inverse function f^-1 reverses f, satisfying f^-1(f(x)) = x; you find it by swapping x and y and solving for y. A function has an inverse only if it is one-to-one (each output comes from a single input). These ideas power data science pipelines, where preprocessing steps compose into a single transform, and inverses let you map predictions back to original units (undoing a log transform or a standardization to recover real-world values).

Worked Example 1

Problem. For f(x) = 2x and g(x) = x + 1, compute (f o g)(3).

  1. Evaluate the inner function: g(3) = 3 + 1 = 4.
  2. Apply f to that: f(4) = 2 * 4 = 8.

Answer. (f o g)(3) = 8

Worked Example 2

Problem. Find the inverse of f(x) = 3x - 6.

  1. Write y = 3x - 6, then swap: x = 3y - 6.
  2. Solve for y: x + 6 = 3y -> y = (x + 6)/3.
  3. So f^-1(x) = (x + 6)/3.

Answer. f^-1(x) = (x + 6)/3

Worked Example 3

Problem. Verify the inverse from Example 2 numerically in Python.

  1. f = lambda x: 3*x - 6
  2. finv = lambda x: (x + 6)/3
  3. print(finv(f(5))) # 5.0
  4. Composing f then its inverse returns the original input.

Answer. finv(f(5)) = 5.0, confirming the inverse.

Common mistakes
  • Assuming f o g equals g o f. Correct idea: composition is generally not commutative; check the order.
  • Confusing the inverse f^-1 with the reciprocal 1/f. Correct idea: the inverse undoes the mapping, it is not one over the function.
  • Trying to invert a non-one-to-one function over its whole domain. Correct idea: restrict the domain (e.g. x >= 0 for x^2) so an inverse exists.
✎ Try it yourself

Problem. For f(x) = x + 4 and g(x) = 2x, compute (g o f)(1) and find f^-1(x).

Solution. (g o f)(1): f(1) = 5, then g(5) = 10. Inverse of f: y = x + 4 -> swap x = y + 4 -> y = x - 4, so f^-1(x) = x - 4.

Reading and plotting graphs with matplotlib

Turning a function rule into a picture you can interpret, using Python's plotting tools.

Plotting makes a function's behavior visible. The standard workflow uses NumPy to build a dense array of x-values with numpy.linspace, evaluates the function on that array (vectorized operations apply elementwise), and passes the x and y arrays to matplotlib.pyplot.plot, then labels axes and shows the figure. Reading a graph means identifying intercepts, slope or curvature, maxima and minima, and asymptotes. For data scientists this is the everyday act of exploratory data analysis: visualizing a relationship reveals trends, outliers, and the right model far faster than tables of numbers. Knowing how to generate and read these plots turns abstract formulas into intuition.

Worked Example 1

Problem. Plot f(x) = x^2 over x from -3 to 3 in Python.

  1. import numpy as np, matplotlib.pyplot as plt
  2. x = np.linspace(-3, 3, 100)
  3. plt.plot(x, x**2); plt.xlabel('x'); plt.ylabel('f(x)'); plt.show()
  4. linspace makes 100 evenly spaced points so the curve looks smooth.

Answer. A smooth upward parabola with its minimum at (0, 0).

Worked Example 2

Problem. From the plot of f(x) = x^2 - 4, read the x-intercepts.

  1. Intercepts occur where the curve crosses the x-axis, i.e. f(x) = 0.
  2. Solve x^2 - 4 = 0 -> x^2 = 4 -> x = ±2.
  3. The graph crosses at (-2, 0) and (2, 0).

Answer. x-intercepts at x = -2 and x = 2.

Worked Example 3

Problem. Plot two functions on the same axes with a legend in Python.

  1. import numpy as np, matplotlib.pyplot as plt
  2. x = np.linspace(-3, 3, 100)
  3. plt.plot(x, x**2, label='x^2'); plt.plot(x, 2*x + 1, label='2x+1')
  4. plt.legend(); plt.show()

Answer. A parabola and a line on one figure, distinguished by the legend.

Common mistakes
  • Using too few points so curves look jagged. Correct idea: use a dense linspace (e.g. 100+ points) for smooth curves.
  • Forgetting plt.show() (or display) so nothing appears. Correct idea: call show after building the plot in a script.
  • Looping element by element to compute y. Correct idea: NumPy lets you apply the rule to the whole array at once (x**2).
✎ Try it yourself

Problem. Write Python to plot f(x) = (x - 1)^2 over x in [-2, 4] and state where the minimum appears.

Solution. import numpy as np, matplotlib.pyplot as plt; x = np.linspace(-2, 4, 100); plt.plot(x, (x - 1)**2); plt.show(). The vertex of (x - 1)^2 is at x = 1, so the minimum appears at (1, 0).

Key terms
  • Function — a rule assigning exactly one output to each input.
  • Domain — the set of allowed inputs to a function.
  • Range — the set of outputs a function actually produces.
  • Slope — the rate of change of a linear function, rise over run.
  • Vertex — the turning point of a parabola.
  • Composition — applying one function to the result of another, (f o g)(x).
  • Inverse function — the function that reverses another, undoing its mapping.
  • Transformation — a shift, stretch, or reflection that moves a graph.
Assignment · Graph Lab

Define f(x) = x^2 and three transformations of it (a vertical shift, a horizontal shift, and a reflection). Predict by hand how each graph differs, then use numpy and matplotlib to plot all four on one axis. Write two sentences confirming whether the plots matched your predictions.

Deliverable · A labeled matplotlib figure with four curves plus a short written comparison.

Quiz · 5 questions
  1. 1. What is the domain of f(x) = 1 / (x - 2)?

  2. 2. A line passes through (0, 3) with slope 2. What is its equation?

  3. 3. The graph of g(x) = (x - 4)^2 compared to x^2 is shifted:

  4. 4. If f(x) = 2x and g(x) = x + 1, what is (f o g)(3)?

  5. 5. Which is true of a function and its inverse?

You'll be able to

I can identify the domain, range, and key features of a function from its rule or graph.

I can sketch transformations of a base function and find inverses.

I can plot a function in Python and interpret its shape.

Weeks 7-8 Unit 4: Exponentials & Logarithms
Exponential modelsThe constant eLogarithm definitionLog lawsChange of baseLog scalesSolving log/exp equations
Lecture
Exponential growth and decay

Quantities that multiply by a fixed factor each period, modeling everything from interest to viral spread.

An exponential function has the form f(x) = a * b^x, where a is the starting value and b is the growth factor. When b > 1 the quantity grows (each step multiplies by b); when 0 < b < 1 it decays. Unlike linear change, which adds a fixed amount, exponential change multiplies by a fixed ratio, so it accelerates dramatically. Doubling every period means b = 2; losing 10% each period means b = 0.9. In data science, exponential models describe compound interest, population and user growth, radioactive or signal decay, and learning-rate schedules. Recognizing the multiplicative pattern, and reading off a and b, lets you forecast and to spot processes that linear thinking would badly underestimate.

Worked Example 1

Problem. A colony of 100 bacteria doubles every hour. How many after 3 hours?

  1. Model: f(t) = 100 * 2^t with t in hours.
  2. f(3) = 100 * 2^3 = 100 * 8.
  3. = 800.

Answer. 800 bacteria

Worked Example 2

Problem. A 200 mg drug dose decays 25% per hour. How much remains after 2 hours?

  1. Decay factor b = 1 - 0.25 = 0.75, so f(t) = 200 * 0.75^t.
  2. f(2) = 200 * 0.75^2 = 200 * 0.5625.
  3. = 112.5 mg.

Answer. 112.5 mg

Worked Example 3

Problem. Compute the first five values of f(t) = 100 * 2^t in Python.

  1. vals = [100 * 2**t for t in range(5)]
  2. print(vals) # [100, 200, 400, 800, 1600]
  3. Each value is exactly twice the previous, the signature of exponential growth.

Answer. [100, 200, 400, 800, 1600]

Common mistakes
  • Treating exponential growth as linear. Correct idea: linear adds a constant; exponential multiplies by a constant factor each step.
  • Using a decay percentage directly as b. Correct idea: a 25% loss means b = 0.75, not 0.25.
  • Putting the variable in the base instead of the exponent. Correct idea: in a * b^x the changing variable x is the exponent.
✎ Try it yourself

Problem. An investment of 1000 dollars grows 10% per year. What is its value after 3 years?

Solution. Growth factor b = 1.10, so f(t) = 1000 * 1.10^t. f(3) = 1000 * 1.10^3 = 1000 * 1.331 = 1331 dollars.

The number e and continuous growth

Why a strange constant near 2.718 is the natural base for growth that compounds instantly.

The number e (approximately 2.71828) is the limit of (1 + 1/n)^n as n grows without bound, the value you approach when growth compounds more and more frequently. It is the natural base for continuous growth: a quantity growing continuously at rate r is modeled by f(t) = a * e^(rt). Because e^x is its own derivative, it sits at the center of calculus, differential equations, and probability. In data science, e appears in the exponential and normal distributions, in the softmax and sigmoid functions, in continuous compounding, and in decay-based learning rates. Treating e as just another base, while remembering its special role, makes these formulas far less mysterious.

Worked Example 1

Problem. Estimate e using (1 + 1/n)^n for n = 1000.

  1. Plug in: (1 + 1/1000)^1000 = 1.001^1000.
  2. This is approximately 2.7169.
  3. As n grows larger the value approaches e = 2.71828...

Answer. About 2.717, approaching e.

Worked Example 2

Problem. 1000 dollars grows continuously at 5% per year. What is its value after 2 years?

  1. Continuous model: f(t) = 1000 * e^(0.05 t).
  2. f(2) = 1000 * e^(0.10).
  3. e^0.10 = 1.10517, so f(2) = 1105.17.

Answer. About 1105.17 dollars

Worked Example 3

Problem. Confirm e and the continuous-growth value in Python.

  1. import math
  2. print(math.e) # 2.718281828459045
  3. print(1000 * math.exp(0.10)) # 1105.1709180756477

Answer. math.e = 2.71828...; the investment is about 1105.17 dollars.

Common mistakes
  • Thinking e is an arbitrary or made-up number. Correct idea: it is the natural limit of continuous compounding and arises unavoidably in growth math.
  • Confusing annual compounding with continuous. Correct idea: continuous growth uses e^(rt), not (1 + r)^t.
  • Forgetting to multiply the rate by time in the exponent. Correct idea: the exponent is r times t, not just r.
✎ Try it yourself

Problem. A culture grows continuously at rate 0.2 per hour starting at 50 cells. How many after 5 hours?

Solution. f(t) = 50 * e^(0.2 t). f(5) = 50 * e^(1.0) = 50 * 2.71828 = 135.9 cells (about 136).

Logarithms as inverses of exponentials

The logarithm answers 'what exponent produces this number?', undoing exponentiation.

A logarithm is the inverse of an exponential: log_b(y) = x means exactly b^x = y. In words, the log asks what power of the base b gives y. So log_2(8) = 3 because 2^3 = 8. Because exp and log undo each other, b^(log_b(y)) = y and log_b(b^x) = x. Logarithms turn multiplication into addition and exponentiation into multiplication, which is why they tame quantities that span many orders of magnitude. In data science they appear in log-likelihood (to avoid tiny-probability underflow), in information theory (bits are log base 2), and in transforming skewed data. Reading a log as 'the exponent' is the key mental move.

Worked Example 1

Problem. Evaluate log_2(16).

  1. Ask: 2 to what power gives 16?
  2. 2^4 = 16.
  3. So log_2(16) = 4.

Answer. 4

Worked Example 2

Problem. Rewrite log_5(125) = 3 in exponential form and verify.

  1. log_b(y) = x means b^x = y.
  2. So log_5(125) = 3 becomes 5^3 = 125.
  3. Check: 5 * 5 * 5 = 125. Correct.

Answer. 5^3 = 125

Worked Example 3

Problem. Compute log base 2 of 8 and natural log of e in Python.

  1. import math
  2. print(math.log2(8)) # 3.0
  3. print(math.log(math.e)) # 1.0
  4. log2 uses base 2; math.log defaults to base e (natural log).

Answer. log2(8) = 3.0 and ln(e) = 1.0.

Common mistakes
  • Thinking log(0) or log of a negative is defined. Correct idea: logarithms are only defined for positive inputs.
  • Reading log_b(y) as b times y. Correct idea: it is the exponent that turns b into y.
  • Assuming log means base 10 in code. Correct idea: in Python math.log is natural log (base e); use math.log10 for base 10.
✎ Try it yourself

Problem. Evaluate log_3(81) and rewrite it in exponential form.

Solution. Ask 3 to what power gives 81: 3^4 = 81, so log_3(81) = 4. In exponential form, 3^4 = 81.

Log laws: product, quotient, and power rules

Three identities that convert products, quotients, and powers into simpler sums and multiples.

The log laws follow directly from exponent rules. The product rule says log(xy) = log(x) + log(y); the quotient rule says log(x/y) = log(x) - log(y); and the power rule says log(x^k) = k * log(x). Together they turn multiplication into addition and exponentiation into multiplication, dramatically simplifying expressions and equations. These laws are everywhere in data science: log-likelihoods sum because logs turn a product of probabilities into a sum, the power rule pulls exponents down when solving exponential equations, and log transforms linearize multiplicative relationships. Applying the laws correctly, in either direction, is a core algebraic skill once logs enter your formulas.

Worked Example 1

Problem. Expand log(8x) using log laws (base 2).

  1. Product rule: log_2(8x) = log_2(8) + log_2(x).
  2. log_2(8) = 3.
  3. So it becomes 3 + log_2(x).

Answer. 3 + log_2(x)

Worked Example 2

Problem. Write log(x^3 / y) as a sum and difference of logs.

  1. Quotient rule: log(x^3) - log(y).
  2. Power rule on the first term: 3 log(x) - log(y).

Answer. 3 log(x) - log(y)

Worked Example 3

Problem. Verify the product rule numerically in Python: log(6) vs log(2) + log(3).

  1. import math
  2. print(math.log(6)) # 1.791759...
  3. print(math.log(2) + math.log(3)) # 1.791759...
  4. Both sides match, confirming log(2*3) = log(2) + log(3).

Answer. Both equal about 1.7918, confirming the product rule.

Common mistakes
  • Writing log(x + y) = log(x) + log(y). Correct idea: the product rule applies to log(xy), not to a sum inside the log.
  • Splitting log(x)/log(y) as log(x) - log(y). Correct idea: the quotient rule needs the quotient inside one log, log(x/y).
  • Forgetting the power rule pulls the whole exponent out. Correct idea: log(x^k) = k log(x), with k as a multiplier.
✎ Try it yourself

Problem. Expand log(100 x^2 / y) completely (base 10).

Solution. Quotient rule: log(100 x^2) - log(y). Product rule: log(100) + log(x^2) - log(y). Power rule and log(100) = 2: 2 + 2 log(x) - log(y).

Change of base and natural logarithms

Converting a log from any base into one your calculator or code supports, and the special role of ln.

The change-of-base formula says log_b(x) = log_c(x) / log_c(b) for any new base c. This lets you compute a logarithm in any base using only natural log (ln, base e) or base-10 log, which is exactly what calculators and most libraries provide. The natural log, ln, is the logarithm with base e and is the default in math and statistics because of e's special calculus properties. In data science you constantly switch bases: information is measured in bits (base 2) but computed with ln, and entropy or log-loss formulas convert between them with a constant factor. Knowing the formula frees you from being stuck with built-in bases only.

Worked Example 1

Problem. Compute log_2(10) using natural logs.

  1. Change of base: log_2(10) = ln(10) / ln(2).
  2. ln(10) = 2.302585, ln(2) = 0.693147.
  3. 2.302585 / 0.693147 = 3.3219.

Answer. About 3.3219

Worked Example 2

Problem. Express log_5(20) as a ratio of base-10 logs and estimate it.

  1. log_5(20) = log10(20) / log10(5).
  2. log10(20) = 1.30103, log10(5) = 0.69897.
  3. 1.30103 / 0.69897 = 1.8614.

Answer. About 1.861

Worked Example 3

Problem. Confirm log_2(10) two ways in Python.

  1. import math
  2. print(math.log(10) / math.log(2)) # 3.321928094887362
  3. print(math.log2(10)) # 3.321928094887362
  4. The change-of-base computation matches the built-in log2.

Answer. Both give 3.321928..., confirming change of base.

Common mistakes
  • Inverting the ratio as ln(b)/ln(x). Correct idea: log_b(x) = ln(x) / ln(b), with the target value on top.
  • Assuming ln means base 10. Correct idea: ln is base e; base-10 log is written log10.
  • Believing you cannot compute an arbitrary base. Correct idea: change of base lets you compute any base from ln or log10.
✎ Try it yourself

Problem. Use change of base to compute log_3(50) with natural logs.

Solution. log_3(50) = ln(50) / ln(3) = 3.912023 / 1.098612 = 3.561. So log_3(50) is about 3.561.

Log scales and why we use them in data science

Plotting on a logarithmic axis so multiplicative patterns and huge ranges become readable.

A log scale spaces values by their logarithm, so equal distances represent equal ratios rather than equal differences: 1, 10, 100, 1000 are evenly spaced. This is invaluable when data spans many orders of magnitude or grows multiplicatively. On a log y-axis, an exponential curve becomes a straight line, because taking the log of a * b^x gives log(a) + x*log(b), a linear function of x. Data scientists use log scales to visualize exponential growth, compress heavy-tailed distributions, compare relative (percentage) changes fairly, and reveal power-law relationships as straight lines on log-log plots. Recognizing when a log scale is appropriate often turns an unreadable chart into an obvious trend.

Worked Example 1

Problem. Why does y = 2^x become a straight line on a log y-axis?

  1. Take the log of both sides: log(y) = log(2^x).
  2. Power rule: log(y) = x * log(2).
  3. This is linear in x with slope log(2), so the plot is a line.

Answer. Because log(y) = x log(2) is linear in x.

Worked Example 2

Problem. On a log10 axis, how far apart are 100 and 100000?

  1. log10(100) = 2 and log10(100000) = 5.
  2. The spacing is the difference of logs: 5 - 2 = 3.
  3. They sit 3 'decades' apart, the same gap as 1 to 1000.

Answer. 3 decades apart

Worked Example 3

Problem. Plot doubling data on a log y-axis in Python.

  1. import numpy as np, matplotlib.pyplot as plt
  2. t = np.arange(8); y = 2.0**t
  3. plt.plot(t, y); plt.yscale('log'); plt.show()
  4. On the log axis the doubling curve appears as a straight line.

Answer. The exponential data plots as a straight line on the log scale.

Common mistakes
  • Trying to plot zero or negative values on a log axis. Correct idea: logs are undefined there; log scales require positive values.
  • Reading log-axis gridlines as equal additive steps. Correct idea: each major gridline is a multiplicative factor (often 10x).
  • Assuming a straight line on a log-log plot means linear data. Correct idea: a straight line on log-log indicates a power law, not a linear relationship.
✎ Try it yourself

Problem. A dataset has values 1, 10, 100, 1000. Explain how they appear on a log10 y-axis.

Solution. Their logs are 0, 1, 2, 3, which are evenly spaced. So on a log10 axis the four points are equally spaced one decade apart, even though their raw values jump by factors of 10.

Solving exponential and logarithmic equations

Using logs to bring an unknown down from an exponent, and exponentials to undo a log.

To solve an exponential equation where the unknown is in the exponent, take the log of both sides and use the power rule to pull the variable down: from b^x = y you get x = log(y)/log(b). To solve a logarithmic equation, exponentiate both sides to cancel the log: from log_b(x) = k you get x = b^k. Always check solutions, since logs reject non-positive arguments, so some apparent answers are extraneous. These techniques let data scientists invert growth and decay models (finding the time to reach a target, a half-life, or a doubling time) and solve for parameters hidden inside exponential or logarithmic expressions.

Worked Example 1

Problem. Solve 10^x = 1000.

  1. Recognize 1000 = 10^3.
  2. So 10^x = 10^3 gives x = 3.
  3. Or take log10 of both sides: x = log10(1000) = 3.

Answer. x = 3

Worked Example 2

Problem. Solve 2^x = 50 for x.

  1. Take log of both sides: log(2^x) = log(50).
  2. Power rule: x log(2) = log(50).
  3. x = log(50)/log(2) = 3.912 / 0.693 = 5.644.

Answer. About x = 5.644

Worked Example 3

Problem. Solve 3 * e^(0.5 t) = 12 and verify in Python.

  1. Divide by 3: e^(0.5 t) = 4.
  2. Take ln: 0.5 t = ln(4) = 1.3863, so t = 2.7726.
  3. import math; print(math.log(4)/0.5) # 2.772588722239781

Answer. About t = 2.773

Common mistakes
  • Taking the log of each term separately, e.g. log(2^x) = x. Correct idea: log(2^x) = x log(2); keep the base's log.
  • Forgetting to isolate the exponential first. Correct idea: divide off any coefficient before taking logs (e.g. divide by 3 in 3 e^t).
  • Accepting solutions that make a log's argument zero or negative. Correct idea: discard extraneous roots that violate the log domain.
✎ Try it yourself

Problem. Solve log_2(x) = 5 and then solve 5^x = 30.

Solution. For log_2(x) = 5, exponentiate: x = 2^5 = 32. For 5^x = 30, take logs: x = log(30)/log(5) = 3.401/1.609 = 2.113. So x = 32 and x = 2.113.

Key terms
  • Exponential function — a function of the form f(x) = a * b^x with b > 0.
  • Base e — Euler's number, about 2.71828, arising from continuous growth.
  • Logarithm — the exponent to which a base must be raised to get a value.
  • Natural log — the logarithm with base e, written ln.
  • Log law — identities like log(ab) = log a + log b.
  • Change of base — log_b(x) = ln(x) / ln(b).
  • Half-life — the time for an exponentially decaying quantity to halve.
  • Log scale — an axis where equal spacing means equal ratios, not equal differences.
Assignment · Growth on a Log Scale

Model a quantity that doubles every period, computing its value for the first eight periods. Plot the values in Python on a linear axis and again on a log y-axis (matplotlib's set_yscale('log')). Write two sentences explaining why the log-scale plot becomes a straight line.

Deliverable · Two plots (linear and log scale) of the same data plus a short written explanation.

Quiz · 5 questions
  1. 1. Rewrite log_2(8) = 3 in exponential form.

  2. 2. Simplify log(a) + log(b).

  3. 3. What is ln(e^5)?

  4. 4. A log scale is useful in data science mainly because it:

  5. 5. Solve 10^x = 1000.

You'll be able to

I can convert between exponential and logarithmic form and apply log laws.

I can explain why log scales reveal multiplicative patterns in data.

I can solve exponential and logarithmic equations algebraically and check them numerically.

Weeks 9-10 Unit 5: Sigma/Pi Notation, Sequences & Series
SequencesSigma notationPi notationIndex manipulationSeries formulasStats in sigma formNotation to code
Lecture
Sequences: arithmetic and geometric patterns

Ordered lists of numbers built by adding a constant or multiplying by a constant.

A sequence is an ordered list of numbers, each called a term. An arithmetic sequence adds a fixed common difference d each step, with nth term a_n = a_1 + (n - 1)d. A geometric sequence multiplies by a fixed common ratio r each step, with nth term a_n = a_1 * r^(n-1). Telling them apart is simple: check whether consecutive terms differ by a constant amount (arithmetic) or a constant factor (geometric). Sequences underpin data science wherever values follow a regular pattern: arithmetic models linear schedules and indices, while geometric models exponential growth, decay, and learning-rate decay. Knowing the nth-term formula lets you jump straight to any term without listing them all.

Worked Example 1

Problem. Find the 10th term of the arithmetic sequence 3, 7, 11, 15, ...

  1. Common difference d = 7 - 3 = 4, first term a_1 = 3.
  2. a_n = a_1 + (n - 1)d = 3 + (10 - 1)*4.
  3. = 3 + 36 = 39.

Answer. 39

Worked Example 2

Problem. Find the 6th term of the geometric sequence 2, 6, 18, ...

  1. Common ratio r = 6 / 2 = 3, first term a_1 = 2.
  2. a_n = a_1 * r^(n-1) = 2 * 3^(6-1).
  3. = 2 * 243 = 486.

Answer. 486

Worked Example 3

Problem. Generate the first six terms of a_n = 2 * 3^(n-1) in Python.

  1. terms = [2 * 3**(n-1) for n in range(1, 7)]
  2. print(terms) # [2, 6, 18, 54, 162, 486]
  3. Each term is 3 times the previous, confirming a geometric sequence.

Answer. [2, 6, 18, 54, 162, 486]

Common mistakes
  • Confusing common difference with common ratio. Correct idea: arithmetic adds d, geometric multiplies by r.
  • Using exponent n instead of n - 1 in the formulas. Correct idea: both nth-term formulas use (n - 1) because the first term needs no step.
  • Assuming a sequence must be arithmetic or geometric. Correct idea: many sequences (like 1, 4, 9, 16) are neither.
✎ Try it yourself

Problem. Is 5, 10, 20, 40 arithmetic or geometric, and what is its 7th term?

Solution. Ratios are 10/5 = 2, 20/10 = 2, so it is geometric with r = 2, a_1 = 5. a_7 = 5 * 2^(7-1) = 5 * 64 = 320.

Sigma notation for sums

The compact symbol that says 'add up these terms as the index runs over a range'.

Sigma notation uses the Greek capital sigma to write a sum compactly. The expression sum from i = 1 to n of a_i means a_1 + a_2 + ... + a_n: the index i starts at the lower bound, increases by 1, and stops at the upper bound, with the body a_i evaluated and added each time. It is shorthand for a loop. Data scientists read and write sigma notation constantly, because nearly every statistic (totals, means, variances, error sums) and many machine-learning losses are defined as sums over data points. Fluency means you can both decode a textbook formula and translate it directly into a Python loop or a vectorized NumPy operation.

Worked Example 1

Problem. Evaluate the sum of i for i = 1 to 5.

  1. Expand: 1 + 2 + 3 + 4 + 5.
  2. Add them: 15.

Answer. 15

Worked Example 2

Problem. Evaluate the sum of (2i + 1) for i = 1 to 4.

  1. Compute each term: i=1 -> 3, i=2 -> 5, i=3 -> 7, i=4 -> 9.
  2. Add them: 3 + 5 + 7 + 9.
  3. = 24.

Answer. 24

Worked Example 3

Problem. Compute the sum of i^2 for i = 1 to 5 in Python.

  1. total = sum(i**2 for i in range(1, 6))
  2. print(total) # 55
  3. range(1, 6) gives the index values 1 through 5, mirroring the bounds.

Answer. 55 (1 + 4 + 9 + 16 + 25)

Common mistakes
  • Getting the upper bound off by one. Correct idea: the sum includes the upper bound, so use range(lower, upper + 1) in Python.
  • Forgetting the body applies to every index value. Correct idea: substitute each i into the whole expression before adding.
  • Confusing the index name with a fixed value. Correct idea: the index is a dummy variable; renaming it does not change the sum.
✎ Try it yourself

Problem. Evaluate the sum of (3i - 2) for i = 1 to 4.

Solution. Terms: i=1 -> 1, i=2 -> 4, i=3 -> 7, i=4 -> 10. Sum = 1 + 4 + 7 + 10 = 22.

Pi notation for products

The product counterpart of sigma: multiply the terms instead of adding them.

Pi notation uses the Greek capital pi to denote a product, exactly parallel to sigma for sums. The expression product from i = 1 to n of a_i means a_1 * a_2 * ... * a_n: the index runs over the range and each term multiplies into a running product. A familiar special case is the factorial, n! = product from i = 1 to n of i. Products matter in data science because a joint probability of independent events is a product of their probabilities, and likelihoods multiply probabilities across data points. Because such products shrink toward zero and underflow, practitioners often take the log, converting the product into a sum via the log laws, which connects pi notation back to sigma notation.

Worked Example 1

Problem. Evaluate the product of i for i = 1 to 4.

  1. Expand: 1 * 2 * 3 * 4.
  2. Multiply step by step: 1*2 = 2, 2*3 = 6, 6*4 = 24.
  3. This is 4! (four factorial).

Answer. 24

Worked Example 2

Problem. Evaluate the product of 2^i for i = 1 to 3.

  1. Terms: 2^1 = 2, 2^2 = 4, 2^3 = 8.
  2. Product: 2 * 4 * 8 = 64.
  3. Equivalently 2^(1+2+3) = 2^6 = 64.

Answer. 64

Worked Example 3

Problem. Compute the product of i for i = 1 to 5 in Python.

  1. import math
  2. from functools import reduce
  3. print(reduce(lambda a, b: a*b, range(1, 6))) # 120
  4. print(math.factorial(5)) # 120

Answer. 120 (which is 5!)

Common mistakes
  • Starting a product accumulator at 0. Correct idea: the multiplicative identity is 1, so initialize a product at 1, not 0.
  • Confusing pi notation with the constant pi. Correct idea: the capital pi means 'product of', unrelated to 3.14159.
  • Letting large products overflow or underflow. Correct idea: take logs to turn the product into a sum when values get extreme.
✎ Try it yourself

Problem. Evaluate the product of (i + 1) for i = 1 to 3.

Solution. Terms: i=1 -> 2, i=2 -> 3, i=3 -> 4. Product = 2 * 3 * 4 = 24.

Index manipulation and reindexing tricks

Shifting or splitting the index of a sum without changing its value.

The index of a summation is a dummy variable, so you can rename it, shift it, or split the range as long as the set of terms added stays the same. Reindexing (a change of variable like j = i - 1) lets you line up two sums so their bodies match, which is essential when combining or comparing formulas. Useful identities include pulling out constants (sum of c*a_i = c * sum of a_i), splitting a sum of two parts (sum of (a_i + b_i) = sum a_i + sum b_i), and separating off boundary terms. Data scientists use these moves to simplify derivations, align vectorized operations, and rewrite loss functions into computable forms. The guiding rule: the manipulation is valid only if it adds exactly the same terms.

Worked Example 1

Problem. Reindex the sum of a_i for i = 2 to 5 to start at j = 1.

  1. Let j = i - 1, so i = j + 1; when i = 2, j = 1, and when i = 5, j = 4.
  2. The body a_i becomes a_(j+1).
  3. Result: sum of a_(j+1) for j = 1 to 4 (the same four terms).

Answer. sum of a_(j+1) for j = 1 to 4

Worked Example 2

Problem. Use the constant rule to evaluate the sum of 3i for i = 1 to 4.

  1. Pull out the constant: 3 * sum of i for i = 1 to 4.
  2. sum of i = 1 to 4 is 10.
  3. 3 * 10 = 30.

Answer. 30

Worked Example 3

Problem. Confirm a reindexing leaves the value unchanged in Python.

  1. a = {2: 5, 3: 8, 4: 1, 5: 9}
  2. orig = sum(a[i] for i in range(2, 6))
  3. shifted = sum(a[j+1] for j in range(1, 5))
  4. print(orig, shifted) # 23 23

Answer. Both sums equal 23, confirming the reindex is valid.

Common mistakes
  • Changing the bounds but not the body when reindexing. Correct idea: substitute the new index into the body too, so the same terms are summed.
  • Pulling a variable (not a constant) out of a sum. Correct idea: only factors independent of the index can come outside the sigma.
  • Splitting a product inside a sum, e.g. sum(a_i b_i) = sum a_i * sum b_i. Correct idea: that is false; only sums of separate terms split.
✎ Try it yourself

Problem. Rewrite the sum of i^2 for i = 0 to 3 as a sum starting at k = 1.

Solution. Let k = i + 1, so i = k - 1; i = 0 gives k = 1, i = 3 gives k = 4. The body i^2 becomes (k - 1)^2. Result: sum of (k - 1)^2 for k = 1 to 4 (same terms: 0, 1, 4, 9, totaling 14).

Arithmetic and geometric series formulas

Closed-form shortcuts for adding all terms of an arithmetic or geometric sequence.

A series is the sum of a sequence's terms, and closed-form formulas let you compute it without adding term by term. For an arithmetic series, the sum of the first n terms is S_n = n/2 * (a_1 + a_n), the count times the average of first and last term. For a geometric series with ratio r not equal to 1, S_n = a_1 * (1 - r^n)/(1 - r); when |r| < 1 and the series is infinite, it converges to a_1/(1 - r). These formulas matter in data science for computing totals efficiently, valuing geometric decay (like discounted future rewards in reinforcement learning), and understanding convergence of iterative processes. They turn an O(n) loop into an O(1) calculation.

Worked Example 1

Problem. Sum the arithmetic series 2 + 5 + 8 + ... + 29.

  1. d = 3, a_1 = 2, a_n = 29; find n: 29 = 2 + (n-1)*3 -> n = 10.
  2. S_n = n/2 * (a_1 + a_n) = 10/2 * (2 + 29).
  3. = 5 * 31 = 155.

Answer. 155

Worked Example 2

Problem. Sum the geometric series 3 + 6 + 12 + 24 + 48.

  1. a_1 = 3, r = 2, n = 5.
  2. S_n = a_1 * (1 - r^n)/(1 - r) = 3 * (1 - 32)/(1 - 2).
  3. = 3 * (-31)/(-1) = 93.

Answer. 93

Worked Example 3

Problem. Find the infinite sum 1 + 1/2 + 1/4 + 1/8 + ... and confirm in Python.

  1. Geometric with a_1 = 1, r = 1/2, |r| < 1, so S = a_1/(1 - r).
  2. S = 1 / (1 - 0.5) = 2.
  3. print(sum(0.5**k for k in range(50))) # 2.0 (to float precision)

Answer. 2

Common mistakes
  • Using the geometric formula when r = 1. Correct idea: if r = 1 every term is equal, so the sum is just n * a_1 (the formula divides by zero).
  • Applying the infinite-sum formula when |r| >= 1. Correct idea: the infinite geometric series only converges when |r| < 1.
  • Miscounting n in the arithmetic series. Correct idea: solve a_n = a_1 + (n-1)d for n first to count the terms correctly.
✎ Try it yourself

Problem. Sum the first 20 terms of 4, 7, 10, 13, ...

Solution. Arithmetic with a_1 = 4, d = 3. a_20 = 4 + 19*3 = 61. S_20 = 20/2 * (4 + 61) = 10 * 65 = 650.

Mean, variance, and dot products written in sigma notation

Seeing the core statistics and the dot product as sums you can read off and code directly.

The most common data-science quantities are defined with sigma notation. The mean is (1/n) * sum of x_i, the average of the values. The (population) variance is (1/n) * sum of (x_i - mean)^2, the average squared deviation from the mean, and its square root is the standard deviation. The dot product of two vectors x and y is sum of x_i * y_i, pairing entries, multiplying, and adding. Recognizing these sigma forms is crucial: it lets you connect a formula in a paper to the function you call in NumPy, and to understand what a statistic is measuring rather than treating np.mean or np.dot as black boxes.

Worked Example 1

Problem. Compute the mean of [2, 4, 9] using the sigma definition.

  1. Sum the values: 2 + 4 + 9 = 15.
  2. Divide by n = 3: 15 / 3.
  3. = 5.

Answer. 5

Worked Example 2

Problem. Compute the population variance of [2, 4, 9].

  1. Mean is 5 (from Example 1).
  2. Squared deviations: (2-5)^2 = 9, (4-5)^2 = 1, (9-5)^2 = 16.
  3. Variance = (9 + 1 + 16)/3 = 26/3 = 8.667.

Answer. About 8.667

Worked Example 3

Problem. Compute the dot product of [1, 2, 3] and [4, 5, 6], by hand and in NumPy.

  1. sum of x_i * y_i = 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32.
  2. import numpy as np
  3. print(np.dot([1, 2, 3], [4, 5, 6])) # 32

Answer. 32

Common mistakes
  • Squaring the sum of deviations instead of summing the squared deviations. Correct idea: variance sums (x_i - mean)^2, not (sum of deviations)^2.
  • Dividing variance by n versus n - 1 carelessly. Correct idea: population variance divides by n, sample variance by n - 1; state which you mean.
  • Adding vectors when a dot product is asked. Correct idea: the dot product multiplies paired entries then sums to a single scalar.
✎ Try it yourself

Problem. Find the mean and population variance of [1, 3, 5, 7].

Solution. Mean = (1 + 3 + 5 + 7)/4 = 16/4 = 4. Squared deviations: 9, 1, 1, 9, summing to 20. Variance = 20/4 = 5.

Translating sigma notation into Python loops and NumPy

Mapping a summation formula to an explicit loop and to faster vectorized code.

A summation translates almost mechanically into code. The index range becomes a Python range, the body becomes the expression inside, and the running total accumulates with += starting from 0, or you use the built-in sum with a generator expression. NumPy goes further: it vectorizes the operation, applying the body to whole arrays at once and summing with np.sum, which is far faster and reads closer to the math. Knowing both forms matters in data science because the explicit loop mirrors the formula for clarity and teaching, while the vectorized version is what you actually deploy for performance on real datasets. Verifying that both agree is a good habit.

Worked Example 1

Problem. Translate the sum of i^2 for i = 1 to n into a Python loop.

  1. total = 0
  2. for i in range(1, n + 1):
  3. total += i**2
  4. The accumulator starts at 0 and adds each squared index.

Answer. A loop accumulating total += i**2 over range(1, n+1).

Worked Example 2

Problem. Write the same sum for n = 5 using NumPy.

  1. import numpy as np
  2. i = np.arange(1, 6)
  3. print(np.sum(i**2)) # 55
  4. The body i**2 applies to the whole array, then np.sum adds them.

Answer. 55

Worked Example 3

Problem. Implement the dot product sum of x_i*y_i both ways and confirm they match.

  1. x = [1, 2, 3]; y = [4, 5, 6]
  2. loop = sum(x[i]*y[i] for i in range(len(x))) # 32
  3. import numpy as np; vec = int(np.dot(x, y)) # 32
  4. print(loop == vec) # True

Answer. Both give 32; the equality check prints True.

Common mistakes
  • Initializing the accumulator at 1 for a sum. Correct idea: a sum starts at 0; only a product starts at 1.
  • Using range(1, n) and missing the last term. Correct idea: to include n, use range(1, n + 1).
  • Mixing Python lists and elementwise math. Correct idea: convert to a NumPy array (or use a comprehension) so operations like **2 apply per element.
✎ Try it yourself

Problem. Write NumPy code to compute the mean of [10, 20, 30, 40] from its sigma definition and give the result.

Solution. import numpy as np; x = np.array([10, 20, 30, 40]); mean = np.sum(x) / x.size. This is 100 / 4 = 25.0, matching np.mean(x).

Key terms
  • Sequence — an ordered list of numbers following a rule.
  • Sigma notation — compact summation using the symbol for sum with an index and bounds.
  • Pi notation — compact product notation using the capital pi symbol.
  • Index — the counter variable that steps through the terms of a sum or product.
  • Arithmetic series — a sum where consecutive terms differ by a constant.
  • Geometric series — a sum where consecutive terms share a constant ratio.
  • Partial sum — the sum of the first n terms of a sequence.
  • Dot product — the sum of products of paired entries from two vectors.
Assignment · Sigma to Code

Write the formula for the mean of n numbers in sigma notation, then implement it twice in Python: once with an explicit for loop accumulating the sum, and once with numpy.mean. Confirm both give the same result on a sample list, and add a one-sentence note on which form mirrors the math more directly.

Deliverable · A script showing the sigma formula in a comment, both implementations, and matching printed results.

Quiz · 5 questions
  1. 1. What does the sum of i from i = 1 to 4 equal?

  2. 2. The capital pi symbol in math denotes a:

  3. 3. Which sequence is geometric?

  4. 4. The expression (1/n) * sum of x_i from 1 to n represents the:

  5. 5. Which Python expression matches the sum of x_i^2 over a list xs?

You'll be able to

I can read and write sums and products in sigma and pi notation.

I can recognize the sigma-notation form of a mean, variance, or dot product.

I can translate a summation into equivalent Python or NumPy code.

Weeks 11-12 Unit 6: Sets, Logic & Proof Intro
Set notationSet operationsTruth tablesImplicationsQuantifiersProof introLogic in Python
Lecture
Sets, elements, and set-builder notation

Defining collections of objects precisely, either by listing or by a membership rule.

A set is a well-defined collection of distinct objects called elements; we write x is in A to say x belongs to A. Sets can be listed by roster, like {1, 2, 3}, or described by set-builder notation, like {x : x > 0}, read as 'the set of all x such that x is greater than 0'. Order and repetition do not matter, so {1, 2, 2} equals {1, 2}. Sets are the foundation of how data scientists describe data: a sample space, the unique categories in a column, the support of a distribution, or a filter condition. Set-builder notation in particular mirrors a boolean filter in code, making it the natural bridge between mathematical description and data selection.

Worked Example 1

Problem. List the elements of {x : x is an integer and 1 <= x <= 5}.

  1. The rule keeps integers from 1 to 5 inclusive.
  2. Enumerate them in order.
  3. Result: {1, 2, 3, 4, 5}.

Answer. {1, 2, 3, 4, 5}

Worked Example 2

Problem. Is 7 an element of A = {x : x is even}? State true or false.

  1. The set contains only even numbers.
  2. 7 is odd, so it does not satisfy the rule.
  3. Therefore 7 is not in A.

Answer. False; 7 is not in A.

Worked Example 3

Problem. Build the set of squares of 1..5 with set-builder logic in Python.

  1. squares = {x**2 for x in range(1, 6)}
  2. print(squares) # {1, 4, 9, 16, 25}
  3. A set comprehension mirrors {x^2 : 1 <= x <= 5} and removes duplicates automatically.

Answer. {1, 4, 9, 16, 25}

Common mistakes
  • Thinking duplicates or order matter in a set. Correct idea: a set holds distinct elements with no inherent order, so {1, 2} = {2, 1, 1}.
  • Reading the colon in set-builder notation as anything but 'such that'. Correct idea: {x : P(x)} means all x for which the condition P holds.
  • Confusing the element symbol with the subset symbol. Correct idea: 'in' relates an element to a set; 'subset of' relates a set to a set.
✎ Try it yourself

Problem. Write the set of all positive multiples of 3 less than 20 in roster form.

Solution. Multiples of 3 below 20 are 3, 6, 9, 12, 15, 18. In roster form: {3, 6, 9, 12, 15, 18}.

Union, intersection, complement, and Venn diagrams

Combining sets with the basic operations and picturing them as overlapping regions.

Set operations build new sets from old ones. The union A union B contains every element in A or B (or both); the intersection A intersect B contains only elements in both; the difference A minus B keeps elements in A but not B; and the complement of A (relative to a universal set) is everything not in A. Venn diagrams picture these as overlapping circles, making the regions intuitive. These operations are the algebra behind data filtering and probability: a union is an 'or' condition, an intersection is an 'and', and the complement is a 'not'. Mastering them lets you reason about combined conditions, joins, and event probabilities precisely.

Worked Example 1

Problem. For A = {1, 2, 3} and B = {2, 3, 4}, find A union B and A intersect B.

  1. Union collects all distinct elements: {1, 2, 3, 4}.
  2. Intersection keeps shared elements: 2 and 3.
  3. So A intersect B = {2, 3}.

Answer. A union B = {1, 2, 3, 4}; A intersect B = {2, 3}.

Worked Example 2

Problem. For the same A and B, find A minus B and B minus A.

  1. A minus B keeps elements of A not in B: only 1.
  2. B minus A keeps elements of B not in A: only 4.
  3. Differences are not symmetric.

Answer. A minus B = {1}; B minus A = {4}.

Worked Example 3

Problem. Compute all four operations in Python with set operators.

  1. A, B = {1, 2, 3}, {2, 3, 4}
  2. print(A | B, A & B) # {1, 2, 3, 4} {2, 3}
  3. print(A - B, A ^ B) # {1} {1, 4}
  4. Here ^ is the symmetric difference (in one set but not both).

Answer. Union {1,2,3,4}, intersection {2,3}, difference {1}, symmetric difference {1,4}.

Common mistakes
  • Swapping union and intersection. Correct idea: union is 'or' (everything in either), intersection is 'and' (only the overlap).
  • Assuming A minus B equals B minus A. Correct idea: set difference is not symmetric; the order matters.
  • Taking a complement without a defined universal set. Correct idea: the complement only makes sense relative to a stated universe of elements.
✎ Try it yourself

Problem. For A = {2, 4, 6, 8} and B = {1, 2, 3, 4}, find A intersect B and A union B.

Solution. Shared elements are 2 and 4, so A intersect B = {2, 4}. All distinct elements give A union B = {1, 2, 3, 4, 6, 8}.

Propositions, truth tables, and logical connectives

Statements that are true or false, and how to combine them with and, or, and not.

A proposition is a statement with a definite truth value, true or false. Logical connectives build compound propositions: AND (conjunction) is true only when both parts are true; OR (disjunction) is true when at least one part is true; NOT (negation) flips the value. A truth table lists every combination of inputs and the resulting output, exhaustively defining a connective. This logic is the backbone of data science computation: boolean masks for filtering, conditions in queries, and the gates inside every algorithm reduce to these connectives. Building a truth table guarantees you understand exactly when a compound condition holds, which prevents subtle bugs in filtering and control flow.

Worked Example 1

Problem. Build the truth table for p AND q.

  1. List all input combinations: (T,T), (T,F), (F,T), (F,F).
  2. AND is true only when both are true.
  3. Outputs: T, F, F, F.

Answer. p AND q is true only for (T,T); false otherwise.

Worked Example 2

Problem. Evaluate (p OR q) AND (NOT p) when p = False, q = True.

  1. p OR q = False OR True = True.
  2. NOT p = NOT False = True.
  3. True AND True = True.

Answer. True

Worked Example 3

Problem. Confirm the AND truth table in Python.

  1. for p in (True, False):
  2. for q in (True, False):
  3. print(p, q, p and q)
  4. # True True True / True False False / False True False / False False False

Answer. Only True and True yields True, matching the AND truth table.

Common mistakes
  • Treating 'or' as exclusive. Correct idea: logical OR is inclusive (true when either or both hold) unless stated as XOR.
  • Confusing AND with OR in filters. Correct idea: AND narrows (both conditions), OR widens (either condition).
  • Forgetting NOT has highest precedence. Correct idea: NOT binds before AND and OR, so parenthesize when unsure.
✎ Try it yourself

Problem. Evaluate NOT(p AND q) when p = True and q = False.

Solution. p AND q = True AND False = False. NOT False = True. So the expression is True.

Implications, converse, and contrapositive

The if-then statement and the related forms that are, or are not, logically equivalent to it.

An implication 'if p then q' (p implies q) claims that whenever p is true, q must be true; it is false only when p is true but q is false. From it we form the converse 'if q then p', the inverse 'if not p then not q', and the contrapositive 'if not q then not p'. The crucial fact is that the contrapositive is logically equivalent to the original, while the converse and inverse are not. This matters in data science when reasoning about conditions and proofs: confusing a statement with its converse is a classic error (e.g. assuming a positive test implies disease), and proving the contrapositive is often easier than proving the original directly.

Worked Example 1

Problem. Write the contrapositive of 'if it rains, then the ground is wet'.

  1. Identify p = 'it rains', q = 'the ground is wet'.
  2. Contrapositive is 'if not q then not p'.
  3. So: 'if the ground is not wet, then it did not rain'.

Answer. If the ground is not wet, then it did not rain.

Worked Example 2

Problem. State the converse of 'if a number is divisible by 4, then it is even' and judge its truth.

  1. Converse swaps p and q: 'if a number is even, then it is divisible by 4'.
  2. Test with 6: it is even but not divisible by 4.
  3. So the converse is false, even though the original is true.

Answer. Converse: 'if even then divisible by 4', which is false.

Worked Example 3

Problem. Show p implies q is false only for (p=True, q=False) with a Python truth table.

  1. for p in (True, False):
  2. for q in (True, False):
  3. print(p, q, (not p) or q) # p->q equals (not p) or q
  4. # only True False prints False

Answer. The implication is False exactly when p is True and q is False.

Common mistakes
  • Assuming the converse follows from the original. Correct idea: p implies q does not give q implies p; they are independent.
  • Thinking an implication is false when p is false. Correct idea: if p is false, p implies q is vacuously true regardless of q.
  • Confusing inverse and contrapositive. Correct idea: the contrapositive (not q implies not p) is equivalent; the inverse (not p implies not q) is not.
✎ Try it yourself

Problem. Give the contrapositive of 'if x > 5 then x > 2' and state whether it is true.

Solution. Contrapositive: 'if x is not > 2 (i.e. x <= 2) then x is not > 5 (i.e. x <= 5)'. This is true: any x <= 2 is certainly <= 5, matching the (true) original.

Quantifiers: for-all and there-exists

Statements about all members of a domain versus the existence of at least one.

Quantifiers extend logic over a whole domain. The universal quantifier 'for all x, P(x)' claims P holds for every element; the existential quantifier 'there exists x such that P(x)' claims at least one element satisfies P. Their negations swap: the negation of 'for all x, P(x)' is 'there exists x such that not P(x)', and vice versa. This matters in data science for stating and disproving claims about datasets: a universal claim ('every record is valid') is refuted by a single counterexample, while an existential claim ('some user churned') needs just one witness. Quantifiers also formalize properties like 'every prediction is within tolerance', central to testing and validation.

Worked Example 1

Problem. Is 'for all x in {2, 4, 6}, x is even' true?

  1. Check each element: 2 even, 4 even, 6 even.
  2. All satisfy the property.
  3. So the universal statement is true.

Answer. True

Worked Example 2

Problem. Negate 'for all x, x > 0' over the integers.

  1. Negation of 'for all' is 'there exists ... not'.
  2. So it becomes 'there exists an integer x such that x <= 0'.
  3. This is true (e.g. x = 0 or x = -1), so the original was false.

Answer. There exists an integer x with x <= 0.

Worked Example 3

Problem. Check both quantifiers over a list in Python.

  1. xs = [2, 4, 5, 6]
  2. print(all(x % 2 == 0 for x in xs)) # False (5 is odd)
  3. print(any(x % 2 == 0 for x in xs)) # True (e.g. 2)
  4. all matches 'for all'; any matches 'there exists'.

Answer. all is False (5 breaks it); any is True.

Common mistakes
  • Disproving a universal claim with an example instead of a counterexample. Correct idea: to refute 'for all', you need one case where it fails.
  • Negating a quantifier without swapping it. Correct idea: not(for all P) becomes (there exists not P), not (for all not P).
  • Reading 'there exists' as 'for all'. Correct idea: existential needs only one witness; universal needs every element.
✎ Try it yourself

Problem. Negate 'there exists a learner who passed every exam'.

Solution. Negating 'there exists' gives 'for all'. The inner 'passed every exam' negates to 'failed at least one exam'. Result: 'for every learner, that learner failed at least one exam'.

Proof techniques: direct, contradiction, and induction (intro)

Three standard ways to establish that a mathematical claim is always true.

A proof is a logical argument showing a statement holds. A direct proof assumes the hypothesis and reasons step by step to the conclusion. A proof by contradiction assumes the statement is false, then derives an impossibility, forcing the statement to be true. Mathematical induction proves a claim for all natural numbers by establishing a base case (it holds for n = 1) and an inductive step (if it holds for n, it holds for n + 1), so it cascades to every n. These methods matter in data science for verifying algorithm correctness, justifying that a procedure terminates or produces the right output, and reasoning rigorously about recursive structures rather than trusting examples alone.

Worked Example 1

Problem. Direct proof: if n is even, then n^2 is even.

  1. Assume n is even, so n = 2k for some integer k.
  2. Then n^2 = (2k)^2 = 4k^2 = 2(2k^2).
  3. This is 2 times an integer, so n^2 is even.

Answer. Proven directly: n even implies n^2 even.

Worked Example 2

Problem. By contradiction, show there is no largest natural number.

  1. Suppose there is a largest natural number, call it N.
  2. Consider N + 1, which is also a natural number and is larger than N.
  3. This contradicts N being largest, so no largest natural number exists.

Answer. Proven by contradiction: no largest natural number exists.

Worked Example 3

Problem. By induction, show the sum 1 + 2 + ... + n = n(n+1)/2, and check n = 5 in Python.

  1. Base case n = 1: left side 1, right side 1*2/2 = 1. Holds.
  2. Inductive step: assume sum to n is n(n+1)/2; add (n+1): n(n+1)/2 + (n+1) = (n+1)(n+2)/2, the formula at n+1.
  3. print(sum(range(1, 6)), 5*6//2) # 15 15

Answer. The formula holds for all n; for n = 5 both give 15.

Common mistakes
  • Treating a few examples as a proof. Correct idea: checking cases is evidence, not proof; a general argument is required.
  • Skipping the base case in induction. Correct idea: without the base case the inductive step has nothing to stand on.
  • In contradiction, forgetting to reach an actual impossibility. Correct idea: the assumption must lead to a clear contradiction, not just an odd-looking result.
✎ Try it yourself

Problem. Give a direct proof that the sum of two even integers is even.

Solution. Let the integers be a = 2m and b = 2k for integers m, k. Then a + b = 2m + 2k = 2(m + k), which is 2 times an integer, hence even. Proven.

Sets and boolean logic in Python

Putting set operations and logical connectives to work in actual Python code.

Python implements sets and boolean logic directly, so the math maps onto code one to one. The set type stores distinct, unordered elements and supports union (|), intersection (&), difference (-), and symmetric difference (^), plus membership tests with in. Boolean logic uses and, or, not, with comparison operators returning True or False, and the built-ins all and any realize the universal and existential quantifiers over an iterable. Data scientists lean on these constantly: deduplicating with a set, filtering rows with boolean masks, checking membership against a lookup set, and validating conditions with all/any. Fluency here turns the abstract logic of this unit into everyday data-wrangling tools.

Worked Example 1

Problem. Use a set to find the unique values in [1, 2, 2, 3, 3, 3].

  1. unique = set([1, 2, 2, 3, 3, 3])
  2. print(unique) # {1, 2, 3}
  3. Converting to a set removes duplicates automatically.

Answer. {1, 2, 3}

Worked Example 2

Problem. Test membership and intersection for two ID sets in Python.

  1. active = {101, 102, 103}; paid = {102, 104}
  2. print(102 in active) # True
  3. print(active & paid) # {102}
  4. The intersection finds users who are both active and paid.

Answer. 102 is in active (True); the intersection is {102}.

Worked Example 3

Problem. Filter a list to even numbers and confirm all kept values are even.

  1. nums = [3, 4, 7, 10, 12]
  2. evens = [n for n in nums if n % 2 == 0] # [4, 10, 12]
  3. print(all(n % 2 == 0 for n in evens)) # True
  4. The comprehension applies an 'and-like' filter; all verifies the universal claim.

Answer. evens = [4, 10, 12], and all() confirms they are all even (True).

Common mistakes
  • Using == to compare list membership instead of in. Correct idea: x in collection tests membership; == compares whole objects.
  • Expecting sets to preserve order or duplicates. Correct idea: Python sets are unordered and hold only distinct elements.
  • Confusing & (set intersection / bitwise) with and (boolean). Correct idea: use & between sets, and between boolean expressions.
✎ Try it yourself

Problem. Given a = {1, 2, 3, 4} and b = {3, 4, 5}, write Python to print their intersection and whether every element of b is positive.

Solution. print(a & b) prints {3, 4}. print(all(x > 0 for x in b)) prints True, since 3, 4, and 5 are all positive.

Key terms
  • Set — a well-defined collection of distinct objects.
  • Set-builder notation — defining a set by a rule, e.g. {x : x > 0}.
  • Union — the set of elements in either of two sets.
  • Intersection — the set of elements common to both sets.
  • Proposition — a statement that is either true or false.
  • Implication — an if-then statement, p implies q.
  • Contrapositive — the equivalent statement not-q implies not-p.
  • Quantifier — for-all or there-exists, specifying scope over a domain.
Assignment · Logic in Sets

Given two sets A and B of integers, compute their union, intersection, and difference by hand, then reproduce all three using Python set operations. Separately, write the contrapositive of the statement 'if a number is divisible by 4 then it is even' and state whether the original is true.

Deliverable · Hand calculations plus a Python snippet using set operators, and the written contrapositive with a true/false judgment.

Quiz · 5 questions
  1. 1. If A = {1, 2, 3} and B = {2, 3, 4}, what is A intersect B?

  2. 2. The contrapositive of 'if p then q' is:

  3. 3. A proposition is best described as a statement that:

  4. 4. Which symbol means 'there exists'?

  5. 5. In Python, A & B for two sets returns the:

You'll be able to

I can use set notation and operations to describe collections of data.

I can build a truth table and identify the contrapositive of a statement.

I can outline a direct proof and recognize a proof by contradiction.

Weeks 13-14 Unit 7: Coordinate Geometry, Trig & Vectors Preview
Distance & midpointLines & slopesCirclesRight-triangle trigUnit circle & radiansVector basicsDot product preview
Lecture
The coordinate plane, distance, and midpoint

Locating points by (x, y) pairs and measuring the gap and center between them.

The coordinate plane locates each point by an ordered pair (x, y): x is the horizontal position, y the vertical. The distance between two points (x1, y1) and (x2, y2) comes from the Pythagorean theorem: sqrt((x2 - x1)^2 + (y2 - y1)^2), the straight-line length of the segment joining them. The midpoint is the average of the coordinates: ((x1 + x2)/2, (y1 + y2)/2). These formulas matter in data science because distance is the foundation of similarity and clustering (k-nearest neighbors, k-means all measure how far points are), and midpoints relate to centroids and averages. The same idea generalizes to many dimensions, which is exactly how feature vectors are compared.

Worked Example 1

Problem. Find the distance between (0, 0) and (3, 4).

  1. distance = sqrt((3 - 0)^2 + (4 - 0)^2).
  2. = sqrt(9 + 16) = sqrt(25).
  3. = 5.

Answer. 5

Worked Example 2

Problem. Find the midpoint of (-2, 5) and (4, 1).

  1. Average the x-coordinates: (-2 + 4)/2 = 1.
  2. Average the y-coordinates: (5 + 1)/2 = 3.
  3. Midpoint is (1, 3).

Answer. (1, 3)

Worked Example 3

Problem. Compute the distance between (1, 2) and (4, 6) in Python.

  1. import math
  2. print(math.dist((1, 2), (4, 6))) # 5.0
  3. math.dist applies the same sqrt of summed squared differences.

Answer. 5.0

Common mistakes
  • Forgetting to square the differences before adding. Correct idea: the distance formula squares each coordinate gap, sums, then takes the root.
  • Subtracting instead of averaging for the midpoint. Correct idea: the midpoint averages the coordinates, ((x1+x2)/2, (y1+y2)/2).
  • Mixing up which coordinate is x and which is y. Correct idea: a point is (x, y) with x horizontal and y vertical.
✎ Try it yourself

Problem. Find the distance and midpoint between (2, 1) and (6, 4).

Solution. Distance = sqrt((6-2)^2 + (4-1)^2) = sqrt(16 + 9) = sqrt(25) = 5. Midpoint = ((2+6)/2, (1+4)/2) = (4, 2.5).

Lines: slope, parallel, and perpendicular relationships

How the slope of a line encodes its direction and relates two lines.

A line's slope m measures steepness as rise over run, (y2 - y1)/(x2 - x1), and its equation in slope-intercept form is y = mx + b. Two distinct lines are parallel when they share the same slope (they never meet), and perpendicular when their slopes are negative reciprocals, so m1 * m2 = -1. A horizontal line has slope 0; a vertical line has undefined slope. These relationships matter in data science for understanding regression lines, decision boundaries, and orthogonality (perpendicularity), which generalizes to the idea of uncorrelated or independent directions in higher dimensions. Recognizing parallel and perpendicular conditions from slopes is a quick, reliable geometric tool.

Worked Example 1

Problem. Are the lines y = 2x + 1 and y = 2x - 4 parallel, perpendicular, or neither?

  1. Read the slopes: both have m = 2.
  2. Equal slopes with different intercepts means parallel.
  3. They never intersect.

Answer. Parallel

Worked Example 2

Problem. Find the slope of a line perpendicular to y = 3x + 5.

  1. The given slope is 3.
  2. Perpendicular slope is the negative reciprocal: -1/3.
  3. Check: 3 * (-1/3) = -1.

Answer. -1/3

Worked Example 3

Problem. In Python, test whether lines through given points are perpendicular.

  1. m1 = (6 - 2)/(3 - 1) # slope 2 through (1,2),(3,6)
  2. m2 = (1 - 3)/(4 - 0) # slope -0.5 through (0,3),(4,1)
  3. print(m1 * m2) # -1.0
  4. A product of -1 confirms the lines are perpendicular.

Answer. m1 * m2 = -1.0, so the lines are perpendicular.

Common mistakes
  • Thinking parallel lines have negative-reciprocal slopes. Correct idea: parallel lines have equal slopes; perpendicular ones have negative reciprocals.
  • Forgetting vertical lines have undefined slope. Correct idea: a vertical line's run is zero, so slope is undefined, not zero.
  • Using just the reciprocal for perpendicularity. Correct idea: it must be the negative reciprocal, so the product of slopes is -1.
✎ Try it yourself

Problem. A line has slope -4. Give the slope of a parallel line and of a perpendicular line.

Solution. A parallel line has the same slope, -4. A perpendicular line has the negative reciprocal: -1/(-4) = 1/4.

Circles and conic basics

The equation of a circle and a first look at the curves called conic sections.

A circle is the set of all points at a fixed distance (the radius r) from a center (h, k); its equation is (x - h)^2 + (y - k)^2 = r^2, which is just the distance formula set equal to r squared. Circles belong to the conic sections, the curves you get by slicing a cone: circles, ellipses, parabolas, and hyperbolas, each with a characteristic quadratic equation. In data science, circular and elliptical level sets appear as contours of distance and of Gaussian distributions, decision boundaries, and confidence regions. Recognizing a circle's center and radius from its equation, by reading off (h, k) and r, is the first step toward interpreting these two-dimensional shapes.

Worked Example 1

Problem. Give the center and radius of (x - 2)^2 + (y + 3)^2 = 25.

  1. Match to (x - h)^2 + (y - k)^2 = r^2.
  2. h = 2 and k = -3 (since y + 3 = y - (-3)).
  3. r^2 = 25 so r = 5.

Answer. Center (2, -3), radius 5.

Worked Example 2

Problem. Write the equation of a circle centered at (0, 0) with radius 4.

  1. With h = 0, k = 0 the equation is x^2 + y^2 = r^2.
  2. r = 4 gives r^2 = 16.
  3. Equation: x^2 + y^2 = 16.

Answer. x^2 + y^2 = 16

Worked Example 3

Problem. In Python, check whether the point (3, 4) lies on the circle x^2 + y^2 = 25.

  1. x, y = 3, 4
  2. print(x**2 + y**2) # 25
  3. print(x**2 + y**2 == 25) # True
  4. The point satisfies the equation, so it is on the circle.

Answer. 3^2 + 4^2 = 25, so (3, 4) is on the circle (True).

Common mistakes
  • Reading the center sign backwards. Correct idea: (x - h) means the center coordinate is +h, so (x + 3) gives h = -3.
  • Using r instead of r^2 on the right side. Correct idea: the right-hand side is the radius squared, not the radius.
  • Confusing a circle with a general ellipse. Correct idea: a circle needs equal coefficients on x^2 and y^2; unequal ones give an ellipse.
✎ Try it yourself

Problem. Find the center and radius of (x + 1)^2 + (y - 4)^2 = 9.

Solution. Matching the standard form, h = -1 (from x + 1) and k = 4, with r^2 = 9 so r = 3. Center (-1, 4), radius 3.

Right-triangle trigonometry: sine, cosine, tangent

The three core ratios relating an angle of a right triangle to its sides.

In a right triangle, the trigonometric ratios relate an acute angle to the side lengths. With respect to an angle theta, sine is opposite over hypotenuse, cosine is adjacent over hypotenuse, and tangent is opposite over adjacent (equivalently sine over cosine). The mnemonic SOH-CAH-TOA captures all three. These ratios let you recover unknown sides or angles from partial information using inverse trig functions. In data science, trigonometry underlies rotations, the geometry of vectors and angles between them, signal processing (sine waves), and cyclic feature encoding (turning hour-of-day into sine and cosine components). Knowing the three ratios and how to invert them is the practical core.

Worked Example 1

Problem. In a right triangle, the opposite side is 3 and the hypotenuse is 5. Find sin(theta).

  1. sine = opposite / hypotenuse.
  2. = 3 / 5.
  3. = 0.6.

Answer. sin(theta) = 0.6

Worked Example 2

Problem. If the opposite side is 4 and the adjacent side is 3, find the angle theta.

  1. tan(theta) = opposite / adjacent = 4 / 3.
  2. theta = arctan(4/3).
  3. = about 53.13 degrees.

Answer. About 53.13 degrees

Worked Example 3

Problem. Compute sin, cos, and tan of 30 degrees in Python.

  1. import math
  2. r = math.radians(30)
  3. print(math.sin(r), math.cos(r), math.tan(r))
  4. # 0.4999999999999999 0.8660254037844387 0.5773502691896257

Answer. sin(30) = 0.5, cos(30) = 0.866, tan(30) = 0.577 (to float precision).

Common mistakes
  • Mixing up which side is opposite and which is adjacent. Correct idea: opposite faces the angle; adjacent touches it (and is not the hypotenuse).
  • Feeding degrees into Python's trig functions. Correct idea: math.sin expects radians, so convert with math.radians first.
  • Forgetting tan = sin/cos and is undefined at 90 degrees. Correct idea: tangent blows up where cosine is zero.
✎ Try it yourself

Problem. A right triangle has adjacent side 12 and hypotenuse 13. Find cos(theta) and the opposite side.

Solution. cos(theta) = adjacent/hypotenuse = 12/13 = 0.923. By Pythagoras the opposite side is sqrt(13^2 - 12^2) = sqrt(169 - 144) = sqrt(25) = 5.

The unit circle and radians

Measuring angles by arc length and reading sine and cosine straight off a radius-1 circle.

The unit circle is the circle of radius 1 centered at the origin. Angles are measured in radians, where the angle equals the arc length on the unit circle, so a full revolution is 2 pi radians (equal to 360 degrees), half is pi, and a right angle is pi/2. For a point on the unit circle at angle theta, its coordinates are exactly (cos theta, sin theta), which extends the trig ratios to any angle, not just those in a right triangle. Radians are the natural unit in calculus and computing because they make derivatives and series clean. Data scientists meet radians whenever they use trig functions in code, encode periodic features, or reason about rotations and angles between vectors.

Worked Example 1

Problem. Convert 180 degrees and 90 degrees to radians.

  1. Multiply degrees by pi/180.
  2. 180 * pi/180 = pi.
  3. 90 * pi/180 = pi/2.

Answer. 180 degrees = pi radians; 90 degrees = pi/2 radians.

Worked Example 2

Problem. Give the coordinates on the unit circle at angle pi/2.

  1. The point is (cos theta, sin theta).
  2. cos(pi/2) = 0 and sin(pi/2) = 1.
  3. So the point is (0, 1), the top of the circle.

Answer. (0, 1)

Worked Example 3

Problem. Confirm the point at angle pi/4 on the unit circle in Python.

  1. import math
  2. print(math.cos(math.pi/4), math.sin(math.pi/4))
  3. # 0.7071067811865476 0.7071067811865475
  4. Both equal sqrt(2)/2, as expected at 45 degrees.

Answer. (0.7071, 0.7071), i.e. (sqrt(2)/2, sqrt(2)/2).

Common mistakes
  • Mixing degrees and radians. Correct idea: a full circle is 2 pi radians = 360 degrees; convert with the factor pi/180.
  • Swapping the coordinates as (sin, cos). Correct idea: the unit-circle point is (cos theta, sin theta), x first.
  • Thinking radians need units like degrees. Correct idea: a radian is a pure ratio (arc length over radius), so it is dimensionless.
✎ Try it yourself

Problem. Convert 270 degrees to radians and give its unit-circle coordinates.

Solution. 270 * pi/180 = 3 pi/2 radians. At 3 pi/2, cos = 0 and sin = -1, so the point is (0, -1), the bottom of the circle.

Vectors: components, magnitude, and direction

Describing a quantity that has both size and direction by its coordinate components.

A vector is a quantity with both magnitude and direction, written by its components, like v = (3, 4), meaning 3 across and 4 up. Its magnitude (length) is sqrt(vx^2 + vy^2), again the Pythagorean theorem, and its direction can be given as the angle theta = arctan(vy/vx). A unit vector points the same way with magnitude 1, obtained by dividing each component by the magnitude. Vectors are the core data structure of machine learning: every data point with several features is a vector, and operations on them drive models. Reading off components, computing magnitude (which becomes the norm), and normalizing are everyday operations once you reach linear algebra.

Worked Example 1

Problem. Find the magnitude of the vector (3, 4).

  1. magnitude = sqrt(vx^2 + vy^2) = sqrt(3^2 + 4^2).
  2. = sqrt(9 + 16) = sqrt(25).
  3. = 5.

Answer. 5

Worked Example 2

Problem. Find the unit vector in the direction of (3, 4).

  1. Magnitude is 5 (from Example 1).
  2. Divide each component by 5: (3/5, 4/5).
  3. = (0.6, 0.8), which has magnitude 1.

Answer. (0.6, 0.8)

Worked Example 3

Problem. Compute the magnitude of (5, 12) with NumPy.

  1. import numpy as np
  2. v = np.array([5, 12])
  3. print(np.linalg.norm(v)) # 13.0
  4. norm computes sqrt(5^2 + 12^2) = 13.

Answer. 13.0

Common mistakes
  • Adding components to get magnitude. Correct idea: magnitude squares the components, sums, then takes the root (it is not vx + vy).
  • Forgetting to divide by the magnitude when normalizing. Correct idea: a unit vector is each component divided by the length.
  • Treating a vector as just a point with no direction. Correct idea: a vector carries direction; its components describe how far along each axis.
✎ Try it yourself

Problem. Find the magnitude and unit vector of (8, 6).

Solution. Magnitude = sqrt(8^2 + 6^2) = sqrt(64 + 36) = sqrt(100) = 10. Unit vector = (8/10, 6/10) = (0.8, 0.6).

Vector addition and the dot product preview

Combining vectors tip to tail and the single number that measures their alignment.

Vectors add componentwise: (a1, a2) + (b1, b2) = (a1 + b1, a2 + b2), geometrically placing them tip to tail. The dot product of two vectors is sum of paired products, a1*b1 + a2*b2, producing a single scalar. It equals |a| |b| cos(theta), where theta is the angle between them, so the dot product measures alignment: positive when they point similarly, zero when perpendicular, negative when opposed. This previews the central operation of machine learning: cosine similarity, projections, and the weighted sums inside neurons are all dot products. Understanding that the dot product turns geometry (angle and length) into one computable number is the bridge from this course into linear algebra.

Worked Example 1

Problem. Add the vectors (1, 2) and (3, 5).

  1. Add the first components: 1 + 3 = 4.
  2. Add the second components: 2 + 5 = 7.
  3. Result: (4, 7).

Answer. (4, 7)

Worked Example 2

Problem. Compute the dot product of (1, 0) and (0, 1), and interpret it.

  1. Dot product = 1*0 + 0*1 = 0.
  2. A dot product of 0 means cos(theta) = 0, so theta = 90 degrees.
  3. The vectors are perpendicular.

Answer. 0, meaning the vectors are perpendicular.

Worked Example 3

Problem. Add two vectors and take their dot product in NumPy.

  1. import numpy as np
  2. a = np.array([2, 3]); b = np.array([4, 1])
  3. print(a + b) # [6 4]
  4. print(np.dot(a, b)) # 11 (2*4 + 3*1)

Answer. a + b = [6, 4]; dot product = 11.

Common mistakes
  • Adding vectors by multiplying components. Correct idea: addition is componentwise, pairing and adding matching entries.
  • Expecting the dot product to be a vector. Correct idea: the dot product returns a single scalar, not a vector.
  • Reading a zero dot product as 'no relationship' generally. Correct idea: a zero dot product specifically means the vectors are perpendicular (orthogonal).
✎ Try it yourself

Problem. For a = (2, 1) and b = (3, 4), find a + b and the dot product a . b.

Solution. Sum: (2 + 3, 1 + 4) = (5, 5). Dot product: 2*3 + 1*4 = 6 + 4 = 10.

Key terms
  • Distance formula — the straight-line distance between two points using Pythagoras.
  • Midpoint — the point halfway between two given points.
  • Slope — the steepness of a line, change in y over change in x.
  • Radian — an angle measure where a full circle is 2 pi radians.
  • Sine — in a right triangle, opposite over hypotenuse.
  • Unit circle — the circle of radius 1 centered at the origin.
  • Vector — a quantity with both magnitude and direction.
  • Dot product — a scalar combining two vectors, foundational for ML similarity.
Assignment · Vectors on the Plane

Given two points, compute by hand the distance between them and the magnitude of the vector from one to the other. Then in Python, represent the points as NumPy arrays, compute the difference vector, its norm with numpy.linalg.norm, and the dot product of two sample vectors. Confirm your hand and code distances match.

Deliverable · Hand calculations plus a NumPy snippet printing the distance, vector magnitude, and a dot product.

Quiz · 5 questions
  1. 1. What is the distance between (0, 0) and (3, 4)?

  2. 2. Two lines are perpendicular when their slopes are:

  3. 3. How many radians are in a full circle?

  4. 4. The magnitude of the vector (3, 4) is:

  5. 5. The dot product of (1, 0) and (0, 1) is:

You'll be able to

I can compute distances, midpoints, and slopes in the coordinate plane.

I can apply basic trigonometry and reason about angles in radians.

I can describe a vector by components and magnitude and add vectors.

Where this leads

Course milestones

Build a single Python notebook that demonstrates each unit's core idea (precision, algebra, functions, logs, summation, sets, vectors) with a worked example.
Read an unfamiliar formula written in sigma and function notation and explain each symbol in plain language.
Reproduce statistics like mean and variance from their sigma-notation definitions in NumPy and verify against built-in functions.
Plot and interpret a dataset on both linear and log scales, justifying which reveals the pattern.
Pass a cumulative readiness check confirming preparedness for the statistics and linear algebra tracks.

Free, forever. Math you can actually use.

Part of the open-source Crunch Academy tech-education path. Pair it with the data-science and ML tracks when you're ready.

All Math for Data Science courses Crunch Academy home