xbe.at

Python / Python for ML and AI

Explaining Polynomial Functions with Python

9 min read, 15 sections

Contents
  1. Introduction to Polynomial Functions
  2. Defining Polynomial Functions
  3. Visualizing Polynomial Functions
  4. Roots of Polynomial Functions
  5. Polynomial Arithmetic
  6. Polynomial Differentiation
  7. Polynomial Interpolation
  8. Polynomial Regression
  9. Real-life Example: Population Growth Model
  10. Real-life Example: Trajectory of a Projectile
  11. Polynomial Curve Fitting
  12. Polynomial Factorization
  13. Polynomial Long Division
  14. Polynomial Composition
  15. Additional Resources

Introduction to Polynomial Functions

Polynomial functions are fundamental mathematical constructs that appear in various fields, from algebra to calculus. In this presentation, we'll explore polynomial functions using Python, demonstrating how to create, manipulate, and analyze them programmatically.

import matplotlib.pyplot as plt

def polynomial(x, coeffs):
    return sum(coeff * x**power for power, coeff in enumerate(coeffs))

x = np.linspace(-5, 5, 100)
y = polynomial(x, [1, 0, 1])  # f(x) = x^2 + 1

plt.plot(x, y)
plt.title("Quadratic Function: f(x) = x^2 + 1")
plt.xlabel("x")
plt.ylabel("f(x)")
plt.grid(True)
plt.show()

Defining Polynomial Functions

A polynomial function is an expression consisting of variables and coefficients, involving only addition, subtraction, multiplication, and non-negative integer exponents. In Python, we can represent polynomials using lists or arrays of coefficients.

    def polynomial(x):
        return sum(coeff * x**power for power, coeff in enumerate(coeffs))
    return polynomial

# Create a polynomial f(x) = 2x^3 - 3x^2 + 4x - 1
f = create_polynomial([-1, 4, -3, 2])

# Evaluate the polynomial at x = 2
result = f(2)
print(f"f(2) = {result}")  # Output: f(2) = 13

Visualizing Polynomial Functions

Visualization is crucial for understanding the behavior of polynomial functions. We can use libraries like Matplotlib to plot polynomials and observe their characteristics.

import matplotlib.pyplot as plt

def plot_polynomial(coeffs, x_range=(-10, 10), num_points=1000):
    x = np.linspace(x_range[0], x_range[1], num_points)
    y = np.polyval(coeffs[::-1], x)
    
    plt.figure(figsize=(10, 6))
    plt.plot(x, y)
    plt.title(f"Polynomial: {np.poly1d(coeffs[::-1])}")
    plt.xlabel("x")
    plt.ylabel("f(x)")
    plt.grid(True)
    plt.axhline(y=0, color='k', linestyle='--')
    plt.axvline(x=0, color='k', linestyle='--')
    plt.show()

# Plot f(x) = x^3 - 2x^2 - x + 2
plot_polynomial([2, -1, -2, 1])

Roots of Polynomial Functions

The roots (or zeros) of a polynomial are the x-values where the function equals zero. Python's NumPy library provides tools to find these roots efficiently.


def find_roots(coeffs):
    # Reverse coefficients for numpy's roots function
    roots = np.roots(coeffs[::-1])
    return roots

# Find roots of x^3 - 6x^2 + 11x - 6
coeffs = [-6, 11, -6, 1]
roots = find_roots(coeffs)

print("Roots:", roots)
print("Verification:")
for root in roots:
    print(f"f({root:.2f}) = {np.polyval(coeffs[::-1], root):.2e}")

Polynomial Arithmetic

Polynomials can be added, subtracted, and multiplied. Python's NumPy library provides convenient functions for these operations.


def polynomial_arithmetic(p1, p2):
    # Addition
    sum_poly = np.polyadd(p1, p2)
    
    # Subtraction
    diff_poly = np.polysub(p1, p2)
    
    # Multiplication
    prod_poly = np.polymul(p1, p2)
    
    return sum_poly, diff_poly, prod_poly

# p1 = x^2 + 2x + 1, p2 = x - 1
p1 = [1, 2, 1]
p2 = [1, -1]

sum_poly, diff_poly, prod_poly = polynomial_arithmetic(p1, p2)

print("p1 + p2 =", np.poly1d(sum_poly))
print("p1 - p2 =", np.poly1d(diff_poly))
print("p1 * p2 =", np.poly1d(prod_poly))

Polynomial Differentiation

The derivative of a polynomial is another polynomial of degree one less than the original. We can implement this operation in Python to analyze the rate of change of polynomial functions.


def differentiate_polynomial(coeffs):
    # Reverse coefficients for numpy's polyder function
    deriv = np.polyder(coeffs[::-1])
    return deriv[::-1]  # Reverse back to our convention

# Differentiate f(x) = x^3 - 2x^2 + 3x - 4
coeffs = [-4, 3, -2, 1]
deriv = differentiate_polynomial(coeffs)

print("Original polynomial:", np.poly1d(coeffs[::-1]))
print("Derivative:", np.poly1d(deriv[::-1]))

# Visualize the original function and its derivative
x = np.linspace(-2, 3, 100)
y_orig = np.polyval(coeffs[::-1], x)
y_deriv = np.polyval(deriv[::-1], x)

plt.figure(figsize=(10, 6))
plt.plot(x, y_orig, label='f(x)')
plt.plot(x, y_deriv, label="f'(x)")
plt.legend()
plt.title("Function and its Derivative")
plt.grid(True)
plt.show()

Polynomial Interpolation

Polynomial interpolation is the process of finding a polynomial that passes through a given set of points. This technique is useful in data fitting and approximation.

import matplotlib.pyplot as plt

def interpolate_polynomial(x, y):
    coeffs = np.polyfit(x, y, len(x) - 1)
    return coeffs[::-1]  # Reverse to match our convention

# Data points
x = np.array([0, 1, 2, 3, 4])
y = np.array([1, 3, 8, 15, 7])

coeffs = interpolate_polynomial(x, y)
print("Interpolating polynomial:", np.poly1d(coeffs[::-1]))

# Visualize the interpolation
x_smooth = np.linspace(0, 4, 100)
y_smooth = np.polyval(coeffs[::-1], x_smooth)

plt.figure(figsize=(10, 6))
plt.scatter(x, y, color='red', label='Data points')
plt.plot(x_smooth, y_smooth, label='Interpolating polynomial')
plt.legend()
plt.title("Polynomial Interpolation")
plt.grid(True)
plt.show()

Polynomial Regression

Polynomial regression is a form of regression analysis where the relationship between the independent variable x and the dependent variable y is modeled as an nth degree polynomial. This technique is useful when data shows a curvilinear relationship.

import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# Generate sample data
np.random.seed(0)
x = np.sort(np.random.uniform(0, 1, 20))
y = np.sin(2 * np.pi * x) + np.random.normal(0, 0.1, 20)

# Perform polynomial regression
degree = 3
poly_features = PolynomialFeatures(degree=degree, include_bias=False)
X_poly = poly_features.fit_transform(x.reshape(-1, 1))

model = LinearRegression()
model.fit(X_poly, y)

# Generate points for plotting the polynomial curve
X_plot = np.linspace(0, 1, 100).reshape(-1, 1)
X_plot_poly = poly_features.transform(X_plot)
y_plot = model.predict(X_plot_poly)

# Plotting
plt.figure(figsize=(10, 6))
plt.scatter(x, y, color='blue', label='Data points')
plt.plot(X_plot, y_plot, color='red', label=f'Polynomial (degree {degree})')
plt.legend()
plt.title("Polynomial Regression")
plt.xlabel("x")
plt.ylabel("y")
plt.grid(True)
plt.show()

# Calculate R-squared score
r2 = r2_score(y, model.predict(X_poly))
print(f"R-squared score: {r2:.4f}")

Real-life Example: Population Growth Model

Polynomial functions can model population growth over time. Let's consider a hypothetical population of bacteria in a petri dish, where the growth is initially exponential but slows down as resources become limited.

import matplotlib.pyplot as plt

def population_model(t, a, b, c):
    return a * t**2 + b * t + c

# Time points (hours)
t = np.linspace(0, 10, 100)

# Model parameters
a = -0.5  # Growth rate deceleration
b = 10    # Initial growth rate
c = 100   # Initial population

# Calculate population
population = population_model(t, a, b, c)

plt.figure(figsize=(10, 6))
plt.plot(t, population)
plt.title("Bacteria Population Growth Model")
plt.xlabel("Time (hours)")
plt.ylabel("Population")
plt.grid(True)
plt.show()

# Predict population at t = 5 hours
t_predict = 5
pop_predict = population_model(t_predict, a, b, c)
print(f"Predicted population at t = {t_predict} hours: {pop_predict:.0f}")

Real-life Example: Trajectory of a Projectile

The path of a projectile under the influence of gravity (ignoring air resistance) can be modeled using a quadratic function. This is a classic application of polynomial functions in physics.

import matplotlib.pyplot as plt

def projectile_trajectory(x, v0, angle):
    g = 9.8  # Acceleration due to gravity (m/s^2)
    angle_rad = np.radians(angle)
    
    # Coefficients of the quadratic function
    a = -0.5 * g / (v0 * np.cos(angle_rad))**2
    b = np.tan(angle_rad)
    c = 0
    
    return a * x**2 + b * x + c

# Initial velocity and launch angle
v0 = 50  # m/s
angle = 45  # degrees

# Generate x coordinates
x = np.linspace(0, 250, 1000)

# Calculate y coordinates
y = projectile_trajectory(x, v0, angle)

plt.figure(figsize=(12, 6))
plt.plot(x, y)
plt.title(f"Projectile Trajectory (v0 = {v0} m/s, angle = {angle}°)")
plt.xlabel("Horizontal distance (m)")
plt.ylabel("Vertical distance (m)")
plt.grid(True)
plt.axis('equal')
plt.show()

# Calculate maximum height and range
max_height = np.max(y)
max_range = x[np.where(y <= 0)[0][0]]

print(f"Maximum height: {max_height:.2f} m")
print(f"Maximum range: {max_range:.2f} m")

Polynomial Curve Fitting

Polynomial curve fitting is a technique used to find the best polynomial function that fits a given set of data points. This method is widely used in data analysis and scientific modeling.

import matplotlib.pyplot as plt

# Generate noisy data
np.random.seed(0)
x = np.linspace(0, 10, 100)
y_true = 3*x**2 - 5*x + 2
y_noisy = y_true + np.random.normal(0, 10, y_true.shape)

# Fit polynomials of different degrees
degrees = [1, 2, 5]
plt.figure(figsize=(12, 4))

for i, degree in enumerate(degrees, 1):
    coeffs = np.polyfit(x, y_noisy, degree)
    y_fit = np.polyval(coeffs, x)
    
    plt.subplot(1, 3, i)
    plt.scatter(x, y_noisy, alpha=0.5, label='Noisy data')
    plt.plot(x, y_true, 'r-', label='True function')
    plt.plot(x, y_fit, 'g-', label=f'Fitted (degree {degree})')
    plt.title(f"Degree {degree} Fit")
    plt.legend()
    plt.xlabel('x')
    plt.ylabel('y')

plt.tight_layout()
plt.show()

# Calculate and print Mean Squared Error for each fit
for degree in degrees:
    coeffs = np.polyfit(x, y_noisy, degree)
    y_fit = np.polyval(coeffs, x)
    mse = np.mean((y_noisy - y_fit)**2)
    print(f"MSE for degree {degree}: {mse:.2f}")

Polynomial Factorization

Polynomial factorization is the process of expressing a polynomial as a product of its factors. This is useful in solving equations and simplifying expressions. While Python doesn't have a built-in function for symbolic factorization, we can use the SymPy library for this purpose.


def factorize_polynomial(poly_expr):
    return factor(poly_expr)

# Define a symbol for the variable
x = symbols('x')

# Create a polynomial expression
poly = x**3 - 2*x**2 - 5*x + 6

print("Original polynomial:", poly)
print("Factored form:", factorize_polynomial(poly))

# Example of expanding a factored polynomial
factored = (x - 3) * (x + 1) * (x - 2)
expanded = expand(factored)

print("\nFactored form:", factored)
print("Expanded form:", expanded)

Polynomial Long Division

Polynomial long division is an algorithm for dividing a polynomial by another polynomial of equal or lower degree. This process is analogous to long division of numbers and is useful in various mathematical applications.


def polynomial_long_division(dividend, divisor):
    quotient = np.zeros(len(dividend) - len(divisor) + 1)
    remainder = np.array(dividend)
    
    for i in range(len(quotient)):
        if len(remainder) < len(divisor):
            break
        term = remainder[0] / divisor[0]
        quotient[i] = term
        if len(remainder) >= len(divisor):
            remainder = remainder[1:] - term * divisor[1:]
    
    remainder = np.trim_zeros(remainder, 'f')
    return quotient, remainder

# Example: (x^3 + 2x^2 - 5x - 6) / (x + 2)
dividend = [1, 2, -5, -6]  # x^3 + 2x^2 - 5x - 6
divisor = [1, 2]           # x + 2

quotient, remainder = polynomial_long_division(dividend, divisor)

print("Quotient:", np.poly1d(quotient))
print("Remainder:", np.poly1d(remainder))

Polynomial Composition

Polynomial composition involves substituting one polynomial into another. This operation is useful in various mathematical and computational applications, including cryptography and computer graphics.


def compose_polynomials(outer, inner):
    result = np.zeros(len(outer) * (len(inner) - 1) + 1)
    for i, coef in enumerate(outer):
        power = len(outer) - i - 1
        term = coef * np.poly1d(inner) ** power
        result += term.coef
    return result

# Example: Let f(x) = x^2 + 2x + 1 and g(x) = 2x + 3
# We'll compute f(g(x))
f = [1, 2, 1]  # x^2 + 2x + 1
g = [2, 3]     # 2x + 3

composed = compose_polynomials(f, g)

print("f(x) =", np.poly1d(f))
print("g(x) =", np.poly1d(g))
print("f(g(x)) =", np.poly1d(composed))

# Verify the result
x = np.linspace(-5, 5, 100)
y_f = np.polyval(f, x)
y_g = np.polyval(g, x)
y_composed = np.polyval(composed, x)
y_verify = np.polyval(f, y_g)

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.plot(x, y_composed, label='f(g(x))')
plt.plot(x, y_verify, '--', label='Verification')
plt.legend()
plt.title("Polynomial Composition: f(g(x))")
plt.xlabel("x")
plt.ylabel("y")
plt.grid(True)
plt.show()

Additional Resources

For those interested in delving deeper into polynomial functions and their applications in Python, here are some valuable resources:

  1. "Numerical Methods in Scientific Computing" by Dahlquist and Björck (2008) ArXiv link: https://arxiv.org/abs/0810.4050
  2. "Polynomials, Basis Functions, and Interpolation" by Trefethen (2011) ArXiv link: https://arxiv.org/abs/1111.5005
  3. "Numerical Algorithms" by Higham (2002) This book provides a comprehensive overview of numerical methods, including polynomial-related algorithms.

These resources offer in-depth explanations and advanced techniques for working with polynomial functions in scientific computing and numerical analysis.

More in Python for ML and AI

  1. Explaining Self-Attention vs. Cross-Attention in Python11 min

    Self-attention and cross-attention are fundamental mechanisms in modern deep learning architectures, particularly in transformer models. These techniques...

  2. Explaining Log Loss Using Python10 min

    Log Loss: Understanding the Fundamental Metric in Classification

  3. Explaining the Embedding Layer in Python8 min

    An embedding layer is a crucial component in many deep learning models, particularly in natural language processing tasks. It transforms discrete input data...

  4. Explaining Dispersion Parameter with Python9 min

    The dispersion parameter is a crucial concept in statistical modeling, particularly in generalized linear models (GLMs). It measures the variability of data...

  5. Explaining Universal Approximation Theorem with Python11 min

    The Universal Approximation Theorem is a fundamental concept in neural networks, stating that a feedforward network with a single hidden layer containing a...

  6. Explaining Back Propagation with Python7 min

    Back propagation is a fundamental algorithm in training neural networks. It's the backbone of how these networks learn from data, adjusting their weights to...