Math: log, exp

Lesson#5 of 9 in project Theory

Logarithms

import math
import numpy as np
# natural log (base e)
math.log(1)      # 0.0
math.log(math.e) # 1.0
math.log(10)     # 2.302
# log base 10
math.log10(100)  # 2.0
math.log10(1000) # 3.0
# log base 2
math.log2(8)     # 3.0
math.log2(1024)  # 10.0
# custom base
math.log(81, 3)  # 4.0 — log base 3 of 81
# on arrays
np.log(np.array([1, 10, 100]))    # [0., 2.30, 4.60]
np.log10(np.array([1, 10, 100]))  # [0., 1., 2.]
np.log2(np.array([1, 2, 4, 8]))   # [0., 1., 2., 3.]


Exponents

# e^x
math.exp(0)  # 1.0
math.exp(1)  # 2.718
math.exp(2)  # 7.389


# power operator
2 ** 8        # 256
2 ** 0.5      # 1.414 — square root
math.pow(3, 4) # 81.0


# on arrays
np.exp(np.array([0, 1, 2, 3]))
# [1., 2.718, 7.389, 20.08]


np.power(np.array([2, 3, 4]), 3)
# [8, 27, 64]


Square & cube roots

math.sqrt(25)   # 5.0
math.sqrt(2)    # 1.414
25 ** 0.5       # 5.0 — same thing
8  ** (1/3)     # 2.0 — cube root
np.sqrt(np.array([4, 9, 16, 25]))
# [2., 3., 4., 5.]


Absolute value

abs(-7)          # 7
math.fabs(-3.5)  # 3.5 — always returns float
np.abs(np.array([-3, -1, 0, 2, -5]))
# [3, 1, 0, 2, 5]


Rounding

round(3.567)     # 4
round(3.567, 2)  # 3.57
math.floor(3.9)  # 3 — always down
math.ceil(3.1)   # 4 — always up
math.trunc(3.9)  # 3 — toward zero
np.round(np.array([1.234, 5.678]), 2)
# [1.23, 5.68]
np.floor(np.array([1.9, 2.1, 3.5]))
# [1., 2., 3.]


Trigonometry

math.sin(math.pi / 2)   # 1.0
math.cos(0)             # 1.0
math.tan(math.pi / 4)   # 1.0
# convert degrees ↔ radians
math.radians(180)        # 3.14159
math.degrees(math.pi)   # 180.0
# on arrays — useful for signal processing, Fourier
angles = np.array([0, 30, 60, 90])
np.sin(np.radians(angles))
# [0., 0.5, 0.866, 1.]


Factorial & combinatorics

math.factorial(5)   # 120
math.factorial(10)  # 3628800
math.comb(10, 3)    # 120 — combinations (order doesn't matter)
math.perm(10, 3)    # 720 — permutations (order matters)


Basics with math module

import math
math.sqrt(16)    # 4.0
math.pow(2, 10)  # 1024.0
2 ** 10          # 1024 — same, more pythonic
math.exp(1)      # e^1 = 2.718...
math.log(math.e) # 1.0  — natural log (base e)
math.log(100, 10)# 2.0  — log base 10
math.log2(8)     # 3.0  — log base 2
math.log10(1000) # 3.0

Constants

math.pi    # 3.14159...
math.e     # 2.71828...
math.inf   # infinity
math.nan   # not a number
Rounding
math.floor(3.9)  # 3 — round down
math.ceil(3.1)   # 4 — round up
round(3.567, 2)  # 3.57
abs(-7)          # 7


Numpy math on arrays (the DS way)

import numpy as np
a = np.array([1, 2, 3, 4])
np.sqrt(a)       # [1., 1.41, 1.73, 2.]
np.exp(a)        # [e, e^2, e^3, e^4]
np.log(a)        # natural log element-wise
np.log2(a)
np.log10(a)
np.power(a, 3)   # [1, 8, 27, 64]
np.abs(a)

Clipping values

a = np.array([-3, 0, 5, 10, 99])
np.clip(a, 0, 10)  # [0, 0, 5, 10, 10]
# useful for capping outliers or keeping values in range

Sigmoid (used everywhere in ML)

def sigmoid(x):
    return 1 / (1 + np.exp(-x))
sigmoid(0)    # 0.5
sigmoid(2)    # 0.88
sigmoid(-2)   # 0.12
# squashes any value into (0, 1)

Softmax (multi-class probabilities)

def softmax(x):
    e = np.exp(x - np.max(x))  # subtract max for stability
    return e / e.sum()
softmax(np.array([1.0, 2.0, 3.0]))
# [0.09, 0.24, 0.67] — sums to 1.0

Log loss (cross-entropy)

y_true = np.array([1, 0, 1])
y_pred = np.array([0.9, 0.1, 0.8])
loss = -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
# 0.164 — lower is better

Normalization

a = np.array([10, 20, 30, 40])
# min-max → [0, 1]
(a - a.min()) / (a.max() - a.min())
# [0., 0.33, 0.67, 1.]
# z-score → mean=0, std=1
(a - a.mean()) / a.std()
# [-1.34, -0.45, 0.45, 1.34]

Factorial & combinations

math.factorial(5)       # 120
math.comb(10, 3)        # 120 — "10 choose 3"
math.perm(10, 3)        # 720 — permutations

Working with infinity and NaN

math.isinf(math.inf)   # True
math.isnan(math.nan)   # True
np.isnan(np.array([1, np.nan, 3]))  # [False, True, False]