# Chapter 4: Supervised Learning Techniques

## 4.1 Linear and Polynomial Regression

Supervised learning stands as one of the most prominent and widely applied branches within the vast field of machine learning. This approach involves training algorithms on labeled datasets, where each input example is meticulously paired with its corresponding output label.

The primary objective of supervised learning is to enable the model to discern and internalize the intricate relationships between input features and target variables. By doing so, the model becomes adept at making accurate predictions for new, previously unseen data points.

The realm of supervised learning encompasses two principal categories, each tailored to address specific types of prediction tasks:

**Regression**: This category deals with continuous target variables, allowing for precise numerical predictions. Examples include forecasting house prices based on various features, estimating temperature changes over time, or predicting a company's future stock prices based on historical data and market indicators.**Classification**: In contrast to regression, classification focuses on categorical target variables. It involves assigning input data to predefined classes or categories. Common applications include determining whether an email is spam or legitimate, diagnosing diseases based on medical test results, or identifying the species of a plant based on its physical characteristics.

This chapter delves into an exploration of the most significant and widely-used supervised learning techniques. We begin by examining the fundamentals of **linear and polynomial regression**, which serve as the cornerstone for understanding more complex regression models.

Subsequently, we transition into the realm of **classification algorithms**, where we will elucidate key methods such as logistic regression, decision trees, and support vector machines. Each of these techniques offers unique strengths and is suited to different types of classification problems, providing a comprehensive toolkit for addressing a wide array of real-world machine learning challenges.

Linear regression is the simplest and most fundamental form of regression analysis in machine learning. This technique models the relationship between one or more input features (independent variables) and a continuous target variable (dependent variable) by fitting a straight line through the data points. The primary goal of linear regression is to find the best-fitting line that minimizes the overall prediction error.

In its simplest form, linear regression assumes a linear relationship between the input and output variables. This means that changes in the input variables result in proportional changes in the output variable. The model learns from labeled training data to determine the optimal parameters (slope and intercept) of the line, which can then be used to make predictions on new, unseen data.

Key characteristics of linear regression include:

- Simplicity: Linear regression offers a straightforward and easily implementable approach, making it an excellent starting point for many regression problems. Its uncomplicated nature allows even those new to machine learning to grasp its concepts quickly and apply them effectively.
- Interpretability: One of the key strengths of linear regression lies in its high degree of interpretability. The coefficients of the model directly represent the impact of each feature on the target variable, allowing for clear insights into the relationships between variables. This transparency is particularly valuable in fields where understanding the underlying factors is as important as making accurate predictions.
- Efficiency: Linear regression demonstrates impressive performance with limited computational resources, particularly when working with smaller datasets. This efficiency makes it an ideal choice for quick analyses or in environments where computational power is constrained, without sacrificing the quality of results.
- Versatility: Despite its apparent simplicity, linear regression possesses remarkable versatility. It can be extended to handle multiple input features through multiple linear regression, allowing for more complex analyses. Furthermore, it can be transformed to model non-linear relationships through techniques like polynomial regression, expanding its applicability to a wider range of real-world scenarios.

While linear regression is powerful in its simplicity, it's important to note that it assumes a linear relationship between variables and may not capture complex, non-linear patterns in the data. In such cases, more advanced regression techniques or machine learning models may be more appropriate.

The line in linear regression is defined by a linear equation, which forms the basis of the model's predictions:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

This equation represents how the model calculates its predictions and can be broken down as follows:

- y is the predicted value (target variable)
- β₀ is the y-intercept (bias term), representing the predicted value when all features are zero
- β₁, β₂, ..., βₙ are the coefficients (weights) that determine the impact of each feature on the prediction
- x₁, x₂, ..., xₙ are the input features (independent variables)
- ε is the error term, accounting for the difference between predicted and actual values

Understanding this equation is crucial as it forms the foundation of linear regression and helps in interpreting the model's behavior and results.

**4.1.1 Linear Regression**

In linear regression, the primary objective is to determine the optimal coefficients (weights) that minimize the discrepancy between the predicted values and the actual values. This process is crucial for creating a model that accurately represents the relationship between the input features and the target variable.

To achieve this goal, linear regression typically employs a technique called "minimizing the **mean squared error (MSE)**". The MSE is a measure of the average squared difference between the predicted values and the actual values. Here's a more detailed explanation of this process:

- 1. Prediction: The model makes predictions based on the current coefficients.
- 2. Error Calculation: For each data point, the difference between the predicted value and the actual value is calculated. This difference is called the error or residual.
- 3. Squaring: Each error is squared. This step serves two purposes:
- It ensures all errors are positive, preventing negative errors from canceling out positive ones.
- It penalizes larger errors more heavily, encouraging the model to minimize outliers.

- 4. Mean Calculation: The average of all these squared errors is computed, resulting in the MSE.
- 5. Optimization: The model adjusts its coefficients to minimize this MSE, typically using techniques like gradient descent.

By iteratively adjusting the coefficients to minimize the MSE, the linear regression model gradually improves its predictions, ultimately finding the line of best fit that most accurately represents the relationship in the data. This process ensures that the model's predictions are as close as possible to the actual values across the entire dataset.

**a. Simple Linear Regression**

In **simple linear regression**, the model focuses on the relationship between a single input feature (independent variable) and one target variable (dependent variable). This straightforward approach allows for an uncomplicated analysis of how changes in the input feature directly affect the target variable.

The simplicity of this method makes it an excellent starting point for understanding regression analysis and provides a foundation for more complex regression techniques.

The equation for simple linear regression can be expressed as:

y = β₀ + β₁x + ε

Where:

- y is the target variable (dependent variable)
- x is the input feature (independent variable)
- β₀ is the y-intercept (the value of y when x is 0)
- β₁ is the slope (the change in y for a unit change in x)
- ε is the error term (accounting for the variability not explained by the linear relationship)

**Example: Simple Linear Regression with Scikit-learn**

`import numpy as np`

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.metrics import mean_squared_error, r2_score

from sklearn.model_selection import train_test_split

# Generate sample data (Hours studied vs. Exam score)

np.random.seed(42)

X = np.random.rand(100, 1) * 10 # 100 random values between 0 and 10

y = 2 * X + 1 + np.random.randn(100, 1) * 2 # Linear relationship with some noise

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Predict for new values

X_new = np.array([[6], [7], [8]])

y_new_pred = model.predict(X_new)

# Plotting the data and the regression line

plt.figure(figsize=(10, 6))

plt.scatter(X_train, y_train, color='blue', label='Training data')

plt.scatter(X_test, y_test, color='green', label='Testing data')

plt.plot(X, model.predict(X), color='red', label='Regression line')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Linear Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True)

plt.show()

# Print results

print(f"Model coefficients: {model.coef_[0][0]:.2f}")

print(f"Model intercept: {model.intercept_[0]:.2f}")

print(f"Mean squared error: {mse:.2f}")

print(f"R-squared score: {r2:.2f}")

print(f"Predicted exam scores for new values (6, 7, 8 hours):")

for hours, score in zip(X_new, y_new_pred):

print(f" {hours[0]} hours: {score[0]:.2f}")

Code Breakdown Explanation:

- Importing Libraries:
- We import numpy for numerical operations, matplotlib for plotting, and various functions from sklearn for machine learning tasks.

- Data Generation:
- Instead of using a small predefined dataset, we generate a larger, more realistic dataset with 100 samples.
- We use numpy's random functions to create hours studied (X) between 0 and 10, and exam scores (y) with a linear relationship plus some random noise.

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:
- Mean Squared Error (MSE): Measures the average squared difference between predicted and actual values.
- R-squared (R2) Score: Indicates the proportion of variance in the dependent variable predictable from the independent variable.

- We make predictions on the test set and calculate two common performance metrics:
- New Predictions:
- We predict exam scores for new values (6, 7, and 8 hours of study).

- Visualization:
- We create a more informative plot that shows:
- Training data points (blue)
- Testing data points (green)
- The regression line (red)

- The plot includes a title, legend, and grid for better readability.

- We create a more informative plot that shows:
- Results Output:
- We print the model's coefficients (slope) and intercept, which define the regression line.
- We display the MSE and R2 score to quantify the model's performance.
- Finally, we show the predicted scores for the new values.

This code example provides a more comprehensive look at the linear regression process, including data generation, model evaluation, and results interpretation. It demonstrates best practices such as data splitting and using multiple evaluation metrics, which are crucial in real-world machine learning applications.

**b. Multiple Linear Regression**

Multiple linear regression is an advanced technique that extends the concept of simple linear regression to include two or more input features (independent variables). This method allows for a more comprehensive analysis of complex relationships in data.

Here's a deeper look at multiple linear regression:

- Model Structure: In multiple linear regression, the model attempts to establish a linear relationship between several independent variables and a single dependent variable (target). The general form of the equation is:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

Where y is the target variable, x₁, x₂, ..., xₙ are the input features, β₀ is the y-intercept, β₁, β₂, ..., βₙ are the coefficients for each feature, and ε is the error term.

- Feature Interaction: Unlike simple linear regression, multiple linear regression can capture how different features interact to influence the target variable. This allows for a more nuanced understanding of the data.
- Coefficient Interpretation: Each coefficient (β) represents the change in the target variable for a one-unit change in the corresponding feature, assuming all other features remain constant. This allows for individual assessment of each feature's impact.
- Increased Complexity: While offering more explanatory power, multiple linear regression also introduces greater complexity. Issues like multicollinearity (high correlation between features) need to be carefully managed.
- Applications: This technique is widely used in various fields such as economics, finance, and social sciences where multiple factors often influence an outcome.

By incorporating multiple features, this model provides a more comprehensive approach to understanding and predicting complex relationships in data, making it a powerful tool in the realm of supervised learning.

**Example: Multiple Linear Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Sample data (Features: hours studied, number of practice tests, Target: exam score)

data = {

'Hours_Studied': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],

'Practice_Tests': [1, 2, 2, 3, 3, 4, 4, 5, 5, 6],

'Exam_Score': [50, 60, 65, 70, 75, 80, 85, 90, 92, 95]

}

df = pd.DataFrame(data)

# Features (X) and target (y)

X = df[['Hours_Studied', 'Practice_Tests']]

y = df['Exam_Score']

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and intercept

print("Model Coefficients:")

print(f"Hours Studied: {model.coef_[0]:.2f}")

print(f"Practice Tests: {model.coef_[1]:.2f}")

print(f"Intercept: {model.intercept_:.2f}")

# Print performance metrics

print(f"\nMean Squared Error: {mse:.2f}")

print(f"R-squared Score: {r2:.2f}")

# Predict exam scores for new data

X_new = np.array([[6, 2], [7, 3], [8, 3]])

y_new_pred = model.predict(X_new)

print("\nPredicted exam scores for new values:")

for i, (hours, tests) in enumerate(X_new):

print(f"Hours Studied: {hours}, Practice Tests: {tests}, Predicted Score: {y_new_pred[i]:.2f}")

# Visualize the results

fig = plt.figure(figsize=(12, 5))

# Plot for Hours Studied

ax1 = fig.add_subplot(121, projection='3d')

ax1.scatter(X['Hours_Studied'], X['Practice_Tests'], y, c='b', marker='o')

ax1.set_xlabel('Hours Studied')

ax1.set_ylabel('Practice Tests')

ax1.set_zlabel('Exam Score')

ax1.set_title('3D Scatter Plot of Data')

# Create a mesh grid for the prediction surface

xx, yy = np.meshgrid(np.linspace(X['Hours_Studied'].min(), X['Hours_Studied'].max(), 10),

np.linspace(X['Practice_Tests'].min(), X['Practice_Tests'].max(), 10))

Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

# Plot the prediction surface

ax1.plot_surface(xx, yy, Z, alpha=0.5)

# Plot residuals

ax2 = fig.add_subplot(122)

ax2.scatter(y_pred, y_test - y_pred, c='r', marker='o')

ax2.set_xlabel('Predicted Values')

ax2.set_ylabel('Residuals')

ax2.set_title('Residual Plot')

ax2.axhline(y=0, color='k', linestyle='--')

plt.tight_layout()

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- We import numpy for numerical operations, pandas for data manipulation, matplotlib for plotting, and various functions from sklearn for machine learning tasks.

- Data Preparation:
- We create a larger dataset with 10 samples, including hours studied, number of practice tests, and exam scores.
- The data is stored in a pandas DataFrame for easy manipulation.

- Data Splitting:
- We split the data into features (X) and target variable (y).
- The data is further split into training (80%) and testing (20%) sets using train_test_split.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:
- Mean Squared Error (MSE): Measures the average squared difference between predicted and actual values.
- R-squared (R2) Score: Indicates the proportion of variance in the dependent variable predictable from the independent variables.

- Model Interpretation:
- We print the coefficients for each feature and the intercept, which helps interpret the model's behavior.

- New Predictions:
- We predict exam scores for new values (combinations of hours studied and practice tests).

- Visualization:
- We create two plots to visualize the results:
- A 3D scatter plot showing the relationship between hours studied, practice tests, and exam scores, along with the prediction surface.
- A residual plot to check for any patterns in the model's errors.

This example provides a more comprehensive look at the multiple linear regression process, including data preparation, model evaluation, interpretation, and visualization. It demonstrates best practices such as data splitting, using multiple evaluation metrics, and visualizing results, which are crucial in real-world machine learning applications.

**4.1.2 Polynomial Regression**

Polynomial regression is an advanced extension of linear regression that enables us to model complex, non-linear relationships between input features and the target variable. This is achieved by incorporating polynomial terms into the regression equation, allowing for a more flexible and nuanced representation of the data.

In essence, polynomial regression transforms the original features by raising them to various powers, creating new features that capture non-linear patterns. For instance, a quadratic relationship can be modeled as:

y = β₀ + β₁x + β₂x² + ε

Where:

- y is the target variable
- x is the input feature
- β₀ is the y-intercept
- β₁ and β₂ are coefficients
- ε is the error term

This equation allows for curved relationships between x and y, as opposed to the straight line of simple linear regression.

It's important to note that despite its name, polynomial regression still utilizes a linear model at its core. The 'polynomial' aspect comes from the transformation applied to the input features. By adding these transformed features (e.g., x², x³, etc.), we create a model that can fit non-linear patterns in the data.

The beauty of this approach lies in its ability to capture complex relationships while retaining the simplicity and interpretability of linear regression. The model remains linear in its parameters (the β coefficients), which means we can still use ordinary least squares for estimation and benefit from the statistical properties of linear models.

However, it's crucial to use polynomial regression judiciously. While it can capture non-linear patterns, using too high a degree polynomial can lead to overfitting, where the model performs well on training data but poorly on new, unseen data. Therefore, selecting the appropriate degree of the polynomial is a key consideration in this technique.

**Applying Polynomial Regression with Scikit-learn**

Scikit-learn provides a powerful tool called `PolynomialFeatures`

that simplifies the process of incorporating polynomial terms into our input features. This class automates the creation of higher-degree polynomial features, allowing us to effortlessly transform our linear regression model into a polynomial one.

By utilizing `PolynomialFeatures`

, we can explore and capture non-linear relationships in our data without manually calculating complex polynomial terms. This feature proves particularly useful when dealing with datasets where the relationship between variables isn't strictly linear, enabling us to model more intricate patterns and potentially improve our predictive accuracy.

**Example: Polynomial Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.preprocessing import PolynomialFeatures

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Generate sample data (Hours studied vs. Exam score with a non-linear relationship)

np.random.seed(42)

X = np.random.rand(100, 1) * 10

y = 3 * X**2 + 2 * X + 5 + np.random.randn(100, 1) * 5

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Create polynomial features (degree 2)

poly = PolynomialFeatures(degree=2)

X_train_poly = poly.fit_transform(X_train)

X_test_poly = poly.transform(X_test)

# Train the polynomial regression model

model = LinearRegression()

model.fit(X_train_poly, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test_poly)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and performance metrics

print("Model Coefficients:")

for i, coef in enumerate(model.coef_[0]):

print(f"Degree {i}: {coef:.4f}")

print(f"Intercept: {model.intercept_[0]:.4f}")

print(f"\nMean Squared Error: {mse:.4f}")

print(f"R-squared Score: {r2:.4f}")

# Predict for new values

X_new = np.array([[6], [7], [8]])

X_new_poly = poly.transform(X_new)

y_new_pred = model.predict(X_new_poly)

print("\nPredicted exam scores for new values:")

for hours, score in zip(X_new, y_new_pred):

print(f"Hours Studied: {hours[0]:.1f}, Predicted Score: {score[0]:.2f}")

# Plot the data and the polynomial regression curve

plt.figure(figsize=(12, 6))

# Scatter plot of original data

plt.scatter(X, y, color='blue', alpha=0.5, label='Original data')

# Polynomial regression curve

X_plot = np.linspace(0, 10, 100).reshape(-1, 1)

X_plot_poly = poly.transform(X_plot)

y_plot = model.predict(X_plot_poly)

plt.plot(X_plot, y_plot, color='red', label='Polynomial regression curve')

# Scatter plot of test data

plt.scatter(X_test, y_test, color='green', alpha=0.7, label='Test data')

# Scatter plot of predictions on test data

plt.scatter(X_test, y_pred, color='orange', alpha=0.7, label='Predictions')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Polynomial Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True, alpha=0.3)

plt.show()

# Residual plot

plt.figure(figsize=(10, 6))

residuals = y_test - y_pred

plt.scatter(y_pred, residuals, color='purple', alpha=0.7)

plt.xlabel("Predicted Values")

plt.ylabel("Residuals")

plt.title("Residual Plot")

plt.axhline(y=0, color='r', linestyle='--')

plt.grid(True, alpha=0.3)

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- We import numpy for numerical operations, pandas for data manipulation, matplotlib for plotting, and various functions from sklearn for machine learning tasks.

- Data Generation:
- We create a synthetic dataset with 100 samples, representing hours studied (X) and exam scores (y).
- The relationship between X and y is non-linear, following a quadratic function with some added noise.

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Feature Engineering:
- We use PolynomialFeatures to create polynomial terms up to degree 2.
- This transforms our input features to include x² terms, allowing the model to capture non-linear relationships.

- Model Training:
- We create a LinearRegression model and fit it to the polynomial-transformed training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:
- Mean Squared Error (MSE): Measures the average squared difference between predicted and actual values.
- R-squared (R2) Score: Indicates the proportion of variance in the dependent variable predictable from the independent variables.

- Model Interpretation:
- We print the coefficients for each polynomial term and the intercept, which helps interpret the model's behavior.

- New Predictions:
- We predict exam scores for new values of hours studied (6, 7, and 8 hours).

- Visualization:
- We create two plots to visualize the results:
- A scatter plot showing the original data, test data, predictions, and the polynomial regression curve.
- A residual plot to check for any patterns in the model's errors.

This example provides a more comprehensive look at the polynomial regression process, including data generation, splitting, model evaluation, interpretation, and visualization. It demonstrates best practices such as using separate training and testing sets, evaluating with multiple metrics, and visualizing both the model fit and residuals.

These practices are crucial in real-world machine learning applications to ensure model reliability and to gain insights into model performance.

In conclusion Linear and polynomial regression are foundational techniques in supervised learning for modeling relationships between input features and continuous target variables.

Linear regression is useful when the relationship is approximately linear, while polynomial regression allows us to capture non-linear relationships by transforming the features. These techniques form the basis for more advanced regression methods and are critical for solving a wide range of predictive modeling tasks.

## 4.1 Linear and Polynomial Regression

Supervised learning stands as one of the most prominent and widely applied branches within the vast field of machine learning. This approach involves training algorithms on labeled datasets, where each input example is meticulously paired with its corresponding output label.

The primary objective of supervised learning is to enable the model to discern and internalize the intricate relationships between input features and target variables. By doing so, the model becomes adept at making accurate predictions for new, previously unseen data points.

The realm of supervised learning encompasses two principal categories, each tailored to address specific types of prediction tasks:

**Regression**: This category deals with continuous target variables, allowing for precise numerical predictions. Examples include forecasting house prices based on various features, estimating temperature changes over time, or predicting a company's future stock prices based on historical data and market indicators.**Classification**: In contrast to regression, classification focuses on categorical target variables. It involves assigning input data to predefined classes or categories. Common applications include determining whether an email is spam or legitimate, diagnosing diseases based on medical test results, or identifying the species of a plant based on its physical characteristics.

This chapter delves into an exploration of the most significant and widely-used supervised learning techniques. We begin by examining the fundamentals of **linear and polynomial regression**, which serve as the cornerstone for understanding more complex regression models.

Subsequently, we transition into the realm of **classification algorithms**, where we will elucidate key methods such as logistic regression, decision trees, and support vector machines. Each of these techniques offers unique strengths and is suited to different types of classification problems, providing a comprehensive toolkit for addressing a wide array of real-world machine learning challenges.

Linear regression is the simplest and most fundamental form of regression analysis in machine learning. This technique models the relationship between one or more input features (independent variables) and a continuous target variable (dependent variable) by fitting a straight line through the data points. The primary goal of linear regression is to find the best-fitting line that minimizes the overall prediction error.

In its simplest form, linear regression assumes a linear relationship between the input and output variables. This means that changes in the input variables result in proportional changes in the output variable. The model learns from labeled training data to determine the optimal parameters (slope and intercept) of the line, which can then be used to make predictions on new, unseen data.

Key characteristics of linear regression include:

- Simplicity: Linear regression offers a straightforward and easily implementable approach, making it an excellent starting point for many regression problems. Its uncomplicated nature allows even those new to machine learning to grasp its concepts quickly and apply them effectively.
- Interpretability: One of the key strengths of linear regression lies in its high degree of interpretability. The coefficients of the model directly represent the impact of each feature on the target variable, allowing for clear insights into the relationships between variables. This transparency is particularly valuable in fields where understanding the underlying factors is as important as making accurate predictions.
- Efficiency: Linear regression demonstrates impressive performance with limited computational resources, particularly when working with smaller datasets. This efficiency makes it an ideal choice for quick analyses or in environments where computational power is constrained, without sacrificing the quality of results.
- Versatility: Despite its apparent simplicity, linear regression possesses remarkable versatility. It can be extended to handle multiple input features through multiple linear regression, allowing for more complex analyses. Furthermore, it can be transformed to model non-linear relationships through techniques like polynomial regression, expanding its applicability to a wider range of real-world scenarios.

While linear regression is powerful in its simplicity, it's important to note that it assumes a linear relationship between variables and may not capture complex, non-linear patterns in the data. In such cases, more advanced regression techniques or machine learning models may be more appropriate.

The line in linear regression is defined by a linear equation, which forms the basis of the model's predictions:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

This equation represents how the model calculates its predictions and can be broken down as follows:

- y is the predicted value (target variable)
- β₀ is the y-intercept (bias term), representing the predicted value when all features are zero
- β₁, β₂, ..., βₙ are the coefficients (weights) that determine the impact of each feature on the prediction
- x₁, x₂, ..., xₙ are the input features (independent variables)
- ε is the error term, accounting for the difference between predicted and actual values

Understanding this equation is crucial as it forms the foundation of linear regression and helps in interpreting the model's behavior and results.

**4.1.1 Linear Regression**

In linear regression, the primary objective is to determine the optimal coefficients (weights) that minimize the discrepancy between the predicted values and the actual values. This process is crucial for creating a model that accurately represents the relationship between the input features and the target variable.

To achieve this goal, linear regression typically employs a technique called "minimizing the **mean squared error (MSE)**". The MSE is a measure of the average squared difference between the predicted values and the actual values. Here's a more detailed explanation of this process:

- 1. Prediction: The model makes predictions based on the current coefficients.
- 2. Error Calculation: For each data point, the difference between the predicted value and the actual value is calculated. This difference is called the error or residual.
- 3. Squaring: Each error is squared. This step serves two purposes:
- It ensures all errors are positive, preventing negative errors from canceling out positive ones.
- It penalizes larger errors more heavily, encouraging the model to minimize outliers.

- 4. Mean Calculation: The average of all these squared errors is computed, resulting in the MSE.
- 5. Optimization: The model adjusts its coefficients to minimize this MSE, typically using techniques like gradient descent.

By iteratively adjusting the coefficients to minimize the MSE, the linear regression model gradually improves its predictions, ultimately finding the line of best fit that most accurately represents the relationship in the data. This process ensures that the model's predictions are as close as possible to the actual values across the entire dataset.

**a. Simple Linear Regression**

In **simple linear regression**, the model focuses on the relationship between a single input feature (independent variable) and one target variable (dependent variable). This straightforward approach allows for an uncomplicated analysis of how changes in the input feature directly affect the target variable.

The simplicity of this method makes it an excellent starting point for understanding regression analysis and provides a foundation for more complex regression techniques.

The equation for simple linear regression can be expressed as:

y = β₀ + β₁x + ε

Where:

- y is the target variable (dependent variable)
- x is the input feature (independent variable)
- β₀ is the y-intercept (the value of y when x is 0)
- β₁ is the slope (the change in y for a unit change in x)
- ε is the error term (accounting for the variability not explained by the linear relationship)

**Example: Simple Linear Regression with Scikit-learn**

`import numpy as np`

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.metrics import mean_squared_error, r2_score

from sklearn.model_selection import train_test_split

# Generate sample data (Hours studied vs. Exam score)

np.random.seed(42)

X = np.random.rand(100, 1) * 10 # 100 random values between 0 and 10

y = 2 * X + 1 + np.random.randn(100, 1) * 2 # Linear relationship with some noise

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Predict for new values

X_new = np.array([[6], [7], [8]])

y_new_pred = model.predict(X_new)

# Plotting the data and the regression line

plt.figure(figsize=(10, 6))

plt.scatter(X_train, y_train, color='blue', label='Training data')

plt.scatter(X_test, y_test, color='green', label='Testing data')

plt.plot(X, model.predict(X), color='red', label='Regression line')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Linear Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True)

plt.show()

# Print results

print(f"Model coefficients: {model.coef_[0][0]:.2f}")

print(f"Model intercept: {model.intercept_[0]:.2f}")

print(f"Mean squared error: {mse:.2f}")

print(f"R-squared score: {r2:.2f}")

print(f"Predicted exam scores for new values (6, 7, 8 hours):")

for hours, score in zip(X_new, y_new_pred):

print(f" {hours[0]} hours: {score[0]:.2f}")

Code Breakdown Explanation:

- Importing Libraries:
- We import numpy for numerical operations, matplotlib for plotting, and various functions from sklearn for machine learning tasks.

- Data Generation:
- Instead of using a small predefined dataset, we generate a larger, more realistic dataset with 100 samples.
- We use numpy's random functions to create hours studied (X) between 0 and 10, and exam scores (y) with a linear relationship plus some random noise.

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:
- R-squared (R2) Score: Indicates the proportion of variance in the dependent variable predictable from the independent variable.

- We make predictions on the test set and calculate two common performance metrics:
- New Predictions:
- We predict exam scores for new values (6, 7, and 8 hours of study).

- Visualization:
- We create a more informative plot that shows:
- Training data points (blue)
- Testing data points (green)
- The regression line (red)

- The plot includes a title, legend, and grid for better readability.

- We create a more informative plot that shows:
- Results Output:
- We print the model's coefficients (slope) and intercept, which define the regression line.
- We display the MSE and R2 score to quantify the model's performance.
- Finally, we show the predicted scores for the new values.

This code example provides a more comprehensive look at the linear regression process, including data generation, model evaluation, and results interpretation. It demonstrates best practices such as data splitting and using multiple evaluation metrics, which are crucial in real-world machine learning applications.

**b. Multiple Linear Regression**

Multiple linear regression is an advanced technique that extends the concept of simple linear regression to include two or more input features (independent variables). This method allows for a more comprehensive analysis of complex relationships in data.

Here's a deeper look at multiple linear regression:

- Model Structure: In multiple linear regression, the model attempts to establish a linear relationship between several independent variables and a single dependent variable (target). The general form of the equation is:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

Where y is the target variable, x₁, x₂, ..., xₙ are the input features, β₀ is the y-intercept, β₁, β₂, ..., βₙ are the coefficients for each feature, and ε is the error term.

- Feature Interaction: Unlike simple linear regression, multiple linear regression can capture how different features interact to influence the target variable. This allows for a more nuanced understanding of the data.
- Coefficient Interpretation: Each coefficient (β) represents the change in the target variable for a one-unit change in the corresponding feature, assuming all other features remain constant. This allows for individual assessment of each feature's impact.
- Increased Complexity: While offering more explanatory power, multiple linear regression also introduces greater complexity. Issues like multicollinearity (high correlation between features) need to be carefully managed.
- Applications: This technique is widely used in various fields such as economics, finance, and social sciences where multiple factors often influence an outcome.

By incorporating multiple features, this model provides a more comprehensive approach to understanding and predicting complex relationships in data, making it a powerful tool in the realm of supervised learning.

**Example: Multiple Linear Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Sample data (Features: hours studied, number of practice tests, Target: exam score)

data = {

'Hours_Studied': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],

'Practice_Tests': [1, 2, 2, 3, 3, 4, 4, 5, 5, 6],

'Exam_Score': [50, 60, 65, 70, 75, 80, 85, 90, 92, 95]

}

df = pd.DataFrame(data)

# Features (X) and target (y)

X = df[['Hours_Studied', 'Practice_Tests']]

y = df['Exam_Score']

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and intercept

print("Model Coefficients:")

print(f"Hours Studied: {model.coef_[0]:.2f}")

print(f"Practice Tests: {model.coef_[1]:.2f}")

print(f"Intercept: {model.intercept_:.2f}")

# Print performance metrics

print(f"\nMean Squared Error: {mse:.2f}")

print(f"R-squared Score: {r2:.2f}")

# Predict exam scores for new data

X_new = np.array([[6, 2], [7, 3], [8, 3]])

y_new_pred = model.predict(X_new)

print("\nPredicted exam scores for new values:")

for i, (hours, tests) in enumerate(X_new):

print(f"Hours Studied: {hours}, Practice Tests: {tests}, Predicted Score: {y_new_pred[i]:.2f}")

# Visualize the results

fig = plt.figure(figsize=(12, 5))

# Plot for Hours Studied

ax1 = fig.add_subplot(121, projection='3d')

ax1.scatter(X['Hours_Studied'], X['Practice_Tests'], y, c='b', marker='o')

ax1.set_xlabel('Hours Studied')

ax1.set_ylabel('Practice Tests')

ax1.set_zlabel('Exam Score')

ax1.set_title('3D Scatter Plot of Data')

# Create a mesh grid for the prediction surface

xx, yy = np.meshgrid(np.linspace(X['Hours_Studied'].min(), X['Hours_Studied'].max(), 10),

np.linspace(X['Practice_Tests'].min(), X['Practice_Tests'].max(), 10))

Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

# Plot the prediction surface

ax1.plot_surface(xx, yy, Z, alpha=0.5)

# Plot residuals

ax2 = fig.add_subplot(122)

ax2.scatter(y_pred, y_test - y_pred, c='r', marker='o')

ax2.set_xlabel('Predicted Values')

ax2.set_ylabel('Residuals')

ax2.set_title('Residual Plot')

ax2.axhline(y=0, color='k', linestyle='--')

plt.tight_layout()

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- We import numpy for numerical operations, pandas for data manipulation, matplotlib for plotting, and various functions from sklearn for machine learning tasks.

- Data Preparation:
- We create a larger dataset with 10 samples, including hours studied, number of practice tests, and exam scores.
- The data is stored in a pandas DataFrame for easy manipulation.

- Data Splitting:
- We split the data into features (X) and target variable (y).
- The data is further split into training (80%) and testing (20%) sets using train_test_split.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:
- R-squared (R2) Score: Indicates the proportion of variance in the dependent variable predictable from the independent variables.

- Model Interpretation:
- We print the coefficients for each feature and the intercept, which helps interpret the model's behavior.

- New Predictions:
- We predict exam scores for new values (combinations of hours studied and practice tests).

- Visualization:
- We create two plots to visualize the results:
- A 3D scatter plot showing the relationship between hours studied, practice tests, and exam scores, along with the prediction surface.
- A residual plot to check for any patterns in the model's errors.

This example provides a more comprehensive look at the multiple linear regression process, including data preparation, model evaluation, interpretation, and visualization. It demonstrates best practices such as data splitting, using multiple evaluation metrics, and visualizing results, which are crucial in real-world machine learning applications.

**4.1.2 Polynomial Regression**

Polynomial regression is an advanced extension of linear regression that enables us to model complex, non-linear relationships between input features and the target variable. This is achieved by incorporating polynomial terms into the regression equation, allowing for a more flexible and nuanced representation of the data.

In essence, polynomial regression transforms the original features by raising them to various powers, creating new features that capture non-linear patterns. For instance, a quadratic relationship can be modeled as:

y = β₀ + β₁x + β₂x² + ε

Where:

- y is the target variable
- x is the input feature
- β₀ is the y-intercept
- β₁ and β₂ are coefficients
- ε is the error term

This equation allows for curved relationships between x and y, as opposed to the straight line of simple linear regression.

It's important to note that despite its name, polynomial regression still utilizes a linear model at its core. The 'polynomial' aspect comes from the transformation applied to the input features. By adding these transformed features (e.g., x², x³, etc.), we create a model that can fit non-linear patterns in the data.

The beauty of this approach lies in its ability to capture complex relationships while retaining the simplicity and interpretability of linear regression. The model remains linear in its parameters (the β coefficients), which means we can still use ordinary least squares for estimation and benefit from the statistical properties of linear models.

However, it's crucial to use polynomial regression judiciously. While it can capture non-linear patterns, using too high a degree polynomial can lead to overfitting, where the model performs well on training data but poorly on new, unseen data. Therefore, selecting the appropriate degree of the polynomial is a key consideration in this technique.

**Applying Polynomial Regression with Scikit-learn**

Scikit-learn provides a powerful tool called `PolynomialFeatures`

that simplifies the process of incorporating polynomial terms into our input features. This class automates the creation of higher-degree polynomial features, allowing us to effortlessly transform our linear regression model into a polynomial one.

By utilizing `PolynomialFeatures`

, we can explore and capture non-linear relationships in our data without manually calculating complex polynomial terms. This feature proves particularly useful when dealing with datasets where the relationship between variables isn't strictly linear, enabling us to model more intricate patterns and potentially improve our predictive accuracy.

**Example: Polynomial Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.preprocessing import PolynomialFeatures

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Generate sample data (Hours studied vs. Exam score with a non-linear relationship)

np.random.seed(42)

X = np.random.rand(100, 1) * 10

y = 3 * X**2 + 2 * X + 5 + np.random.randn(100, 1) * 5

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Create polynomial features (degree 2)

poly = PolynomialFeatures(degree=2)

X_train_poly = poly.fit_transform(X_train)

X_test_poly = poly.transform(X_test)

# Train the polynomial regression model

model = LinearRegression()

model.fit(X_train_poly, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test_poly)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and performance metrics

print("Model Coefficients:")

for i, coef in enumerate(model.coef_[0]):

print(f"Degree {i}: {coef:.4f}")

print(f"Intercept: {model.intercept_[0]:.4f}")

print(f"\nMean Squared Error: {mse:.4f}")

print(f"R-squared Score: {r2:.4f}")

# Predict for new values

X_new = np.array([[6], [7], [8]])

X_new_poly = poly.transform(X_new)

y_new_pred = model.predict(X_new_poly)

print("\nPredicted exam scores for new values:")

for hours, score in zip(X_new, y_new_pred):

print(f"Hours Studied: {hours[0]:.1f}, Predicted Score: {score[0]:.2f}")

# Plot the data and the polynomial regression curve

plt.figure(figsize=(12, 6))

# Scatter plot of original data

plt.scatter(X, y, color='blue', alpha=0.5, label='Original data')

# Polynomial regression curve

X_plot = np.linspace(0, 10, 100).reshape(-1, 1)

X_plot_poly = poly.transform(X_plot)

y_plot = model.predict(X_plot_poly)

plt.plot(X_plot, y_plot, color='red', label='Polynomial regression curve')

# Scatter plot of test data

plt.scatter(X_test, y_test, color='green', alpha=0.7, label='Test data')

# Scatter plot of predictions on test data

plt.scatter(X_test, y_pred, color='orange', alpha=0.7, label='Predictions')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Polynomial Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True, alpha=0.3)

plt.show()

# Residual plot

plt.figure(figsize=(10, 6))

residuals = y_test - y_pred

plt.scatter(y_pred, residuals, color='purple', alpha=0.7)

plt.xlabel("Predicted Values")

plt.ylabel("Residuals")

plt.title("Residual Plot")

plt.axhline(y=0, color='r', linestyle='--')

plt.grid(True, alpha=0.3)

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- Data Generation:
- We create a synthetic dataset with 100 samples, representing hours studied (X) and exam scores (y).
- The relationship between X and y is non-linear, following a quadratic function with some added noise.

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Feature Engineering:
- We use PolynomialFeatures to create polynomial terms up to degree 2.
- This transforms our input features to include x² terms, allowing the model to capture non-linear relationships.

- Model Training:
- We create a LinearRegression model and fit it to the polynomial-transformed training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:

- Model Interpretation:
- We print the coefficients for each polynomial term and the intercept, which helps interpret the model's behavior.

- New Predictions:
- We predict exam scores for new values of hours studied (6, 7, and 8 hours).

- Visualization:
- We create two plots to visualize the results:
- A scatter plot showing the original data, test data, predictions, and the polynomial regression curve.
- A residual plot to check for any patterns in the model's errors.

This example provides a more comprehensive look at the polynomial regression process, including data generation, splitting, model evaluation, interpretation, and visualization. It demonstrates best practices such as using separate training and testing sets, evaluating with multiple metrics, and visualizing both the model fit and residuals.

These practices are crucial in real-world machine learning applications to ensure model reliability and to gain insights into model performance.

In conclusion Linear and polynomial regression are foundational techniques in supervised learning for modeling relationships between input features and continuous target variables.

Linear regression is useful when the relationship is approximately linear, while polynomial regression allows us to capture non-linear relationships by transforming the features. These techniques form the basis for more advanced regression methods and are critical for solving a wide range of predictive modeling tasks.

## 4.1 Linear and Polynomial Regression

Supervised learning stands as one of the most prominent and widely applied branches within the vast field of machine learning. This approach involves training algorithms on labeled datasets, where each input example is meticulously paired with its corresponding output label.

The primary objective of supervised learning is to enable the model to discern and internalize the intricate relationships between input features and target variables. By doing so, the model becomes adept at making accurate predictions for new, previously unseen data points.

The realm of supervised learning encompasses two principal categories, each tailored to address specific types of prediction tasks:

**Regression**: This category deals with continuous target variables, allowing for precise numerical predictions. Examples include forecasting house prices based on various features, estimating temperature changes over time, or predicting a company's future stock prices based on historical data and market indicators.**Classification**: In contrast to regression, classification focuses on categorical target variables. It involves assigning input data to predefined classes or categories. Common applications include determining whether an email is spam or legitimate, diagnosing diseases based on medical test results, or identifying the species of a plant based on its physical characteristics.

This chapter delves into an exploration of the most significant and widely-used supervised learning techniques. We begin by examining the fundamentals of **linear and polynomial regression**, which serve as the cornerstone for understanding more complex regression models.

Subsequently, we transition into the realm of **classification algorithms**, where we will elucidate key methods such as logistic regression, decision trees, and support vector machines. Each of these techniques offers unique strengths and is suited to different types of classification problems, providing a comprehensive toolkit for addressing a wide array of real-world machine learning challenges.

Linear regression is the simplest and most fundamental form of regression analysis in machine learning. This technique models the relationship between one or more input features (independent variables) and a continuous target variable (dependent variable) by fitting a straight line through the data points. The primary goal of linear regression is to find the best-fitting line that minimizes the overall prediction error.

In its simplest form, linear regression assumes a linear relationship between the input and output variables. This means that changes in the input variables result in proportional changes in the output variable. The model learns from labeled training data to determine the optimal parameters (slope and intercept) of the line, which can then be used to make predictions on new, unseen data.

Key characteristics of linear regression include:

- Simplicity: Linear regression offers a straightforward and easily implementable approach, making it an excellent starting point for many regression problems. Its uncomplicated nature allows even those new to machine learning to grasp its concepts quickly and apply them effectively.
- Interpretability: One of the key strengths of linear regression lies in its high degree of interpretability. The coefficients of the model directly represent the impact of each feature on the target variable, allowing for clear insights into the relationships between variables. This transparency is particularly valuable in fields where understanding the underlying factors is as important as making accurate predictions.
- Efficiency: Linear regression demonstrates impressive performance with limited computational resources, particularly when working with smaller datasets. This efficiency makes it an ideal choice for quick analyses or in environments where computational power is constrained, without sacrificing the quality of results.
- Versatility: Despite its apparent simplicity, linear regression possesses remarkable versatility. It can be extended to handle multiple input features through multiple linear regression, allowing for more complex analyses. Furthermore, it can be transformed to model non-linear relationships through techniques like polynomial regression, expanding its applicability to a wider range of real-world scenarios.

While linear regression is powerful in its simplicity, it's important to note that it assumes a linear relationship between variables and may not capture complex, non-linear patterns in the data. In such cases, more advanced regression techniques or machine learning models may be more appropriate.

The line in linear regression is defined by a linear equation, which forms the basis of the model's predictions:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

This equation represents how the model calculates its predictions and can be broken down as follows:

- y is the predicted value (target variable)
- β₀ is the y-intercept (bias term), representing the predicted value when all features are zero
- β₁, β₂, ..., βₙ are the coefficients (weights) that determine the impact of each feature on the prediction
- x₁, x₂, ..., xₙ are the input features (independent variables)
- ε is the error term, accounting for the difference between predicted and actual values

Understanding this equation is crucial as it forms the foundation of linear regression and helps in interpreting the model's behavior and results.

**4.1.1 Linear Regression**

In linear regression, the primary objective is to determine the optimal coefficients (weights) that minimize the discrepancy between the predicted values and the actual values. This process is crucial for creating a model that accurately represents the relationship between the input features and the target variable.

To achieve this goal, linear regression typically employs a technique called "minimizing the **mean squared error (MSE)**". The MSE is a measure of the average squared difference between the predicted values and the actual values. Here's a more detailed explanation of this process:

- 1. Prediction: The model makes predictions based on the current coefficients.
- 2. Error Calculation: For each data point, the difference between the predicted value and the actual value is calculated. This difference is called the error or residual.
- 3. Squaring: Each error is squared. This step serves two purposes:
- It ensures all errors are positive, preventing negative errors from canceling out positive ones.
- It penalizes larger errors more heavily, encouraging the model to minimize outliers.

- 4. Mean Calculation: The average of all these squared errors is computed, resulting in the MSE.
- 5. Optimization: The model adjusts its coefficients to minimize this MSE, typically using techniques like gradient descent.

By iteratively adjusting the coefficients to minimize the MSE, the linear regression model gradually improves its predictions, ultimately finding the line of best fit that most accurately represents the relationship in the data. This process ensures that the model's predictions are as close as possible to the actual values across the entire dataset.

**a. Simple Linear Regression**

In **simple linear regression**, the model focuses on the relationship between a single input feature (independent variable) and one target variable (dependent variable). This straightforward approach allows for an uncomplicated analysis of how changes in the input feature directly affect the target variable.

The simplicity of this method makes it an excellent starting point for understanding regression analysis and provides a foundation for more complex regression techniques.

The equation for simple linear regression can be expressed as:

y = β₀ + β₁x + ε

Where:

- y is the target variable (dependent variable)
- x is the input feature (independent variable)
- β₀ is the y-intercept (the value of y when x is 0)
- β₁ is the slope (the change in y for a unit change in x)
- ε is the error term (accounting for the variability not explained by the linear relationship)

**Example: Simple Linear Regression with Scikit-learn**

`import numpy as np`

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.metrics import mean_squared_error, r2_score

from sklearn.model_selection import train_test_split

# Generate sample data (Hours studied vs. Exam score)

np.random.seed(42)

X = np.random.rand(100, 1) * 10 # 100 random values between 0 and 10

y = 2 * X + 1 + np.random.randn(100, 1) * 2 # Linear relationship with some noise

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Predict for new values

X_new = np.array([[6], [7], [8]])

y_new_pred = model.predict(X_new)

# Plotting the data and the regression line

plt.figure(figsize=(10, 6))

plt.scatter(X_train, y_train, color='blue', label='Training data')

plt.scatter(X_test, y_test, color='green', label='Testing data')

plt.plot(X, model.predict(X), color='red', label='Regression line')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Linear Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True)

plt.show()

# Print results

print(f"Model coefficients: {model.coef_[0][0]:.2f}")

print(f"Model intercept: {model.intercept_[0]:.2f}")

print(f"Mean squared error: {mse:.2f}")

print(f"R-squared score: {r2:.2f}")

print(f"Predicted exam scores for new values (6, 7, 8 hours):")

for hours, score in zip(X_new, y_new_pred):

print(f" {hours[0]} hours: {score[0]:.2f}")

Code Breakdown Explanation:

- Importing Libraries:
- We import numpy for numerical operations, matplotlib for plotting, and various functions from sklearn for machine learning tasks.

- Data Generation:
- Instead of using a small predefined dataset, we generate a larger, more realistic dataset with 100 samples.
- We use numpy's random functions to create hours studied (X) between 0 and 10, and exam scores (y) with a linear relationship plus some random noise.

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:
- R-squared (R2) Score: Indicates the proportion of variance in the dependent variable predictable from the independent variable.

- We make predictions on the test set and calculate two common performance metrics:
- New Predictions:
- We predict exam scores for new values (6, 7, and 8 hours of study).

- Visualization:
- We create a more informative plot that shows:
- Training data points (blue)
- Testing data points (green)
- The regression line (red)

- The plot includes a title, legend, and grid for better readability.

- We create a more informative plot that shows:
- Results Output:
- We print the model's coefficients (slope) and intercept, which define the regression line.
- We display the MSE and R2 score to quantify the model's performance.
- Finally, we show the predicted scores for the new values.

This code example provides a more comprehensive look at the linear regression process, including data generation, model evaluation, and results interpretation. It demonstrates best practices such as data splitting and using multiple evaluation metrics, which are crucial in real-world machine learning applications.

**b. Multiple Linear Regression**

Multiple linear regression is an advanced technique that extends the concept of simple linear regression to include two or more input features (independent variables). This method allows for a more comprehensive analysis of complex relationships in data.

Here's a deeper look at multiple linear regression:

- Model Structure: In multiple linear regression, the model attempts to establish a linear relationship between several independent variables and a single dependent variable (target). The general form of the equation is:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

Where y is the target variable, x₁, x₂, ..., xₙ are the input features, β₀ is the y-intercept, β₁, β₂, ..., βₙ are the coefficients for each feature, and ε is the error term.

- Feature Interaction: Unlike simple linear regression, multiple linear regression can capture how different features interact to influence the target variable. This allows for a more nuanced understanding of the data.
- Coefficient Interpretation: Each coefficient (β) represents the change in the target variable for a one-unit change in the corresponding feature, assuming all other features remain constant. This allows for individual assessment of each feature's impact.
- Increased Complexity: While offering more explanatory power, multiple linear regression also introduces greater complexity. Issues like multicollinearity (high correlation between features) need to be carefully managed.
- Applications: This technique is widely used in various fields such as economics, finance, and social sciences where multiple factors often influence an outcome.

By incorporating multiple features, this model provides a more comprehensive approach to understanding and predicting complex relationships in data, making it a powerful tool in the realm of supervised learning.

**Example: Multiple Linear Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Sample data (Features: hours studied, number of practice tests, Target: exam score)

data = {

'Hours_Studied': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],

'Practice_Tests': [1, 2, 2, 3, 3, 4, 4, 5, 5, 6],

'Exam_Score': [50, 60, 65, 70, 75, 80, 85, 90, 92, 95]

}

df = pd.DataFrame(data)

# Features (X) and target (y)

X = df[['Hours_Studied', 'Practice_Tests']]

y = df['Exam_Score']

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and intercept

print("Model Coefficients:")

print(f"Hours Studied: {model.coef_[0]:.2f}")

print(f"Practice Tests: {model.coef_[1]:.2f}")

print(f"Intercept: {model.intercept_:.2f}")

# Print performance metrics

print(f"\nMean Squared Error: {mse:.2f}")

print(f"R-squared Score: {r2:.2f}")

# Predict exam scores for new data

X_new = np.array([[6, 2], [7, 3], [8, 3]])

y_new_pred = model.predict(X_new)

print("\nPredicted exam scores for new values:")

for i, (hours, tests) in enumerate(X_new):

print(f"Hours Studied: {hours}, Practice Tests: {tests}, Predicted Score: {y_new_pred[i]:.2f}")

# Visualize the results

fig = plt.figure(figsize=(12, 5))

# Plot for Hours Studied

ax1 = fig.add_subplot(121, projection='3d')

ax1.scatter(X['Hours_Studied'], X['Practice_Tests'], y, c='b', marker='o')

ax1.set_xlabel('Hours Studied')

ax1.set_ylabel('Practice Tests')

ax1.set_zlabel('Exam Score')

ax1.set_title('3D Scatter Plot of Data')

# Create a mesh grid for the prediction surface

xx, yy = np.meshgrid(np.linspace(X['Hours_Studied'].min(), X['Hours_Studied'].max(), 10),

np.linspace(X['Practice_Tests'].min(), X['Practice_Tests'].max(), 10))

Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

# Plot the prediction surface

ax1.plot_surface(xx, yy, Z, alpha=0.5)

# Plot residuals

ax2 = fig.add_subplot(122)

ax2.scatter(y_pred, y_test - y_pred, c='r', marker='o')

ax2.set_xlabel('Predicted Values')

ax2.set_ylabel('Residuals')

ax2.set_title('Residual Plot')

ax2.axhline(y=0, color='k', linestyle='--')

plt.tight_layout()

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- Data Preparation:
- We create a larger dataset with 10 samples, including hours studied, number of practice tests, and exam scores.
- The data is stored in a pandas DataFrame for easy manipulation.

- Data Splitting:
- We split the data into features (X) and target variable (y).
- The data is further split into training (80%) and testing (20%) sets using train_test_split.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:

- Model Interpretation:
- We print the coefficients for each feature and the intercept, which helps interpret the model's behavior.

- New Predictions:
- We predict exam scores for new values (combinations of hours studied and practice tests).

- Visualization:
- We create two plots to visualize the results:
- A 3D scatter plot showing the relationship between hours studied, practice tests, and exam scores, along with the prediction surface.
- A residual plot to check for any patterns in the model's errors.

This example provides a more comprehensive look at the multiple linear regression process, including data preparation, model evaluation, interpretation, and visualization. It demonstrates best practices such as data splitting, using multiple evaluation metrics, and visualizing results, which are crucial in real-world machine learning applications.

**4.1.2 Polynomial Regression**

Polynomial regression is an advanced extension of linear regression that enables us to model complex, non-linear relationships between input features and the target variable. This is achieved by incorporating polynomial terms into the regression equation, allowing for a more flexible and nuanced representation of the data.

In essence, polynomial regression transforms the original features by raising them to various powers, creating new features that capture non-linear patterns. For instance, a quadratic relationship can be modeled as:

y = β₀ + β₁x + β₂x² + ε

Where:

- y is the target variable
- x is the input feature
- β₀ is the y-intercept
- β₁ and β₂ are coefficients
- ε is the error term

This equation allows for curved relationships between x and y, as opposed to the straight line of simple linear regression.

It's important to note that despite its name, polynomial regression still utilizes a linear model at its core. The 'polynomial' aspect comes from the transformation applied to the input features. By adding these transformed features (e.g., x², x³, etc.), we create a model that can fit non-linear patterns in the data.

The beauty of this approach lies in its ability to capture complex relationships while retaining the simplicity and interpretability of linear regression. The model remains linear in its parameters (the β coefficients), which means we can still use ordinary least squares for estimation and benefit from the statistical properties of linear models.

However, it's crucial to use polynomial regression judiciously. While it can capture non-linear patterns, using too high a degree polynomial can lead to overfitting, where the model performs well on training data but poorly on new, unseen data. Therefore, selecting the appropriate degree of the polynomial is a key consideration in this technique.

**Applying Polynomial Regression with Scikit-learn**

Scikit-learn provides a powerful tool called `PolynomialFeatures`

that simplifies the process of incorporating polynomial terms into our input features. This class automates the creation of higher-degree polynomial features, allowing us to effortlessly transform our linear regression model into a polynomial one.

By utilizing `PolynomialFeatures`

, we can explore and capture non-linear relationships in our data without manually calculating complex polynomial terms. This feature proves particularly useful when dealing with datasets where the relationship between variables isn't strictly linear, enabling us to model more intricate patterns and potentially improve our predictive accuracy.

**Example: Polynomial Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.preprocessing import PolynomialFeatures

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Generate sample data (Hours studied vs. Exam score with a non-linear relationship)

np.random.seed(42)

X = np.random.rand(100, 1) * 10

y = 3 * X**2 + 2 * X + 5 + np.random.randn(100, 1) * 5

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Create polynomial features (degree 2)

poly = PolynomialFeatures(degree=2)

X_train_poly = poly.fit_transform(X_train)

X_test_poly = poly.transform(X_test)

# Train the polynomial regression model

model = LinearRegression()

model.fit(X_train_poly, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test_poly)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and performance metrics

print("Model Coefficients:")

for i, coef in enumerate(model.coef_[0]):

print(f"Degree {i}: {coef:.4f}")

print(f"Intercept: {model.intercept_[0]:.4f}")

print(f"\nMean Squared Error: {mse:.4f}")

print(f"R-squared Score: {r2:.4f}")

# Predict for new values

X_new = np.array([[6], [7], [8]])

X_new_poly = poly.transform(X_new)

y_new_pred = model.predict(X_new_poly)

print("\nPredicted exam scores for new values:")

for hours, score in zip(X_new, y_new_pred):

print(f"Hours Studied: {hours[0]:.1f}, Predicted Score: {score[0]:.2f}")

# Plot the data and the polynomial regression curve

plt.figure(figsize=(12, 6))

# Scatter plot of original data

plt.scatter(X, y, color='blue', alpha=0.5, label='Original data')

# Polynomial regression curve

X_plot = np.linspace(0, 10, 100).reshape(-1, 1)

X_plot_poly = poly.transform(X_plot)

y_plot = model.predict(X_plot_poly)

plt.plot(X_plot, y_plot, color='red', label='Polynomial regression curve')

# Scatter plot of test data

plt.scatter(X_test, y_test, color='green', alpha=0.7, label='Test data')

# Scatter plot of predictions on test data

plt.scatter(X_test, y_pred, color='orange', alpha=0.7, label='Predictions')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Polynomial Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True, alpha=0.3)

plt.show()

# Residual plot

plt.figure(figsize=(10, 6))

residuals = y_test - y_pred

plt.scatter(y_pred, residuals, color='purple', alpha=0.7)

plt.xlabel("Predicted Values")

plt.ylabel("Residuals")

plt.title("Residual Plot")

plt.axhline(y=0, color='r', linestyle='--')

plt.grid(True, alpha=0.3)

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- Data Generation:
- We create a synthetic dataset with 100 samples, representing hours studied (X) and exam scores (y).
- The relationship between X and y is non-linear, following a quadratic function with some added noise.

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Feature Engineering:
- We use PolynomialFeatures to create polynomial terms up to degree 2.
- This transforms our input features to include x² terms, allowing the model to capture non-linear relationships.

- Model Training:
- We create a LinearRegression model and fit it to the polynomial-transformed training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:

- Model Interpretation:
- We print the coefficients for each polynomial term and the intercept, which helps interpret the model's behavior.

- New Predictions:
- We predict exam scores for new values of hours studied (6, 7, and 8 hours).

- Visualization:
- We create two plots to visualize the results:
- A scatter plot showing the original data, test data, predictions, and the polynomial regression curve.
- A residual plot to check for any patterns in the model's errors.

This example provides a more comprehensive look at the polynomial regression process, including data generation, splitting, model evaluation, interpretation, and visualization. It demonstrates best practices such as using separate training and testing sets, evaluating with multiple metrics, and visualizing both the model fit and residuals.

These practices are crucial in real-world machine learning applications to ensure model reliability and to gain insights into model performance.

In conclusion Linear and polynomial regression are foundational techniques in supervised learning for modeling relationships between input features and continuous target variables.

Linear regression is useful when the relationship is approximately linear, while polynomial regression allows us to capture non-linear relationships by transforming the features. These techniques form the basis for more advanced regression methods and are critical for solving a wide range of predictive modeling tasks.

## 4.1 Linear and Polynomial Regression

**Regression**: This category deals with continuous target variables, allowing for precise numerical predictions. Examples include forecasting house prices based on various features, estimating temperature changes over time, or predicting a company's future stock prices based on historical data and market indicators.**Classification**: In contrast to regression, classification focuses on categorical target variables. It involves assigning input data to predefined classes or categories. Common applications include determining whether an email is spam or legitimate, diagnosing diseases based on medical test results, or identifying the species of a plant based on its physical characteristics.

**linear and polynomial regression**, which serve as the cornerstone for understanding more complex regression models.

**classification algorithms**, where we will elucidate key methods such as logistic regression, decision trees, and support vector machines. Each of these techniques offers unique strengths and is suited to different types of classification problems, providing a comprehensive toolkit for addressing a wide array of real-world machine learning challenges.

Key characteristics of linear regression include:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

This equation represents how the model calculates its predictions and can be broken down as follows:

- y is the predicted value (target variable)
- β₀ is the y-intercept (bias term), representing the predicted value when all features are zero
- x₁, x₂, ..., xₙ are the input features (independent variables)
- ε is the error term, accounting for the difference between predicted and actual values

**4.1.1 Linear Regression**

**mean squared error (MSE)**". The MSE is a measure of the average squared difference between the predicted values and the actual values. Here's a more detailed explanation of this process:

- 1. Prediction: The model makes predictions based on the current coefficients.
- 3. Squaring: Each error is squared. This step serves two purposes:
- It ensures all errors are positive, preventing negative errors from canceling out positive ones.
- It penalizes larger errors more heavily, encouraging the model to minimize outliers.

- 4. Mean Calculation: The average of all these squared errors is computed, resulting in the MSE.

**a. Simple Linear Regression**

**simple linear regression**, the model focuses on the relationship between a single input feature (independent variable) and one target variable (dependent variable). This straightforward approach allows for an uncomplicated analysis of how changes in the input feature directly affect the target variable.

The equation for simple linear regression can be expressed as:

y = β₀ + β₁x + ε

Where:

- y is the target variable (dependent variable)
- x is the input feature (independent variable)
- β₀ is the y-intercept (the value of y when x is 0)
- β₁ is the slope (the change in y for a unit change in x)
- ε is the error term (accounting for the variability not explained by the linear relationship)

**Example: Simple Linear Regression with Scikit-learn**

`import numpy as np`

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.metrics import mean_squared_error, r2_score

from sklearn.model_selection import train_test_split

# Generate sample data (Hours studied vs. Exam score)

np.random.seed(42)

X = np.random.rand(100, 1) * 10 # 100 random values between 0 and 10

y = 2 * X + 1 + np.random.randn(100, 1) * 2 # Linear relationship with some noise

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Predict for new values

X_new = np.array([[6], [7], [8]])

y_new_pred = model.predict(X_new)

# Plotting the data and the regression line

plt.figure(figsize=(10, 6))

plt.scatter(X_train, y_train, color='blue', label='Training data')

plt.scatter(X_test, y_test, color='green', label='Testing data')

plt.plot(X, model.predict(X), color='red', label='Regression line')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Linear Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True)

plt.show()

# Print results

print(f"Model coefficients: {model.coef_[0][0]:.2f}")

print(f"Model intercept: {model.intercept_[0]:.2f}")

print(f"Mean squared error: {mse:.2f}")

print(f"R-squared score: {r2:.2f}")

print(f"Predicted exam scores for new values (6, 7, 8 hours):")

for hours, score in zip(X_new, y_new_pred):

print(f" {hours[0]} hours: {score[0]:.2f}")

Code Breakdown Explanation:

- Importing Libraries:
- Data Generation:
- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:

- We make predictions on the test set and calculate two common performance metrics:
- New Predictions:
- We predict exam scores for new values (6, 7, and 8 hours of study).

- Visualization:
- We create a more informative plot that shows:
- Training data points (blue)
- Testing data points (green)
- The regression line (red)

- The plot includes a title, legend, and grid for better readability.

- We create a more informative plot that shows:
- Results Output:
- We print the model's coefficients (slope) and intercept, which define the regression line.
- We display the MSE and R2 score to quantify the model's performance.
- Finally, we show the predicted scores for the new values.

**b. Multiple Linear Regression**

Here's a deeper look at multiple linear regression:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

**Example: Multiple Linear Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Sample data (Features: hours studied, number of practice tests, Target: exam score)

data = {

'Hours_Studied': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],

'Practice_Tests': [1, 2, 2, 3, 3, 4, 4, 5, 5, 6],

'Exam_Score': [50, 60, 65, 70, 75, 80, 85, 90, 92, 95]

}

df = pd.DataFrame(data)

# Features (X) and target (y)

X = df[['Hours_Studied', 'Practice_Tests']]

y = df['Exam_Score']

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Initialize and train the linear regression model

model = LinearRegression()

model.fit(X_train, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and intercept

print("Model Coefficients:")

print(f"Hours Studied: {model.coef_[0]:.2f}")

print(f"Practice Tests: {model.coef_[1]:.2f}")

print(f"Intercept: {model.intercept_:.2f}")

# Print performance metrics

print(f"\nMean Squared Error: {mse:.2f}")

print(f"R-squared Score: {r2:.2f}")

# Predict exam scores for new data

X_new = np.array([[6, 2], [7, 3], [8, 3]])

y_new_pred = model.predict(X_new)

print("\nPredicted exam scores for new values:")

for i, (hours, tests) in enumerate(X_new):

print(f"Hours Studied: {hours}, Practice Tests: {tests}, Predicted Score: {y_new_pred[i]:.2f}")

# Visualize the results

fig = plt.figure(figsize=(12, 5))

# Plot for Hours Studied

ax1 = fig.add_subplot(121, projection='3d')

ax1.scatter(X['Hours_Studied'], X['Practice_Tests'], y, c='b', marker='o')

ax1.set_xlabel('Hours Studied')

ax1.set_ylabel('Practice Tests')

ax1.set_zlabel('Exam Score')

ax1.set_title('3D Scatter Plot of Data')

# Create a mesh grid for the prediction surface

xx, yy = np.meshgrid(np.linspace(X['Hours_Studied'].min(), X['Hours_Studied'].max(), 10),

np.linspace(X['Practice_Tests'].min(), X['Practice_Tests'].max(), 10))

Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

# Plot the prediction surface

ax1.plot_surface(xx, yy, Z, alpha=0.5)

# Plot residuals

ax2 = fig.add_subplot(122)

ax2.scatter(y_pred, y_test - y_pred, c='r', marker='o')

ax2.set_xlabel('Predicted Values')

ax2.set_ylabel('Residuals')

ax2.set_title('Residual Plot')

ax2.axhline(y=0, color='k', linestyle='--')

plt.tight_layout()

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- Data Preparation:
- The data is stored in a pandas DataFrame for easy manipulation.

- Data Splitting:
- We split the data into features (X) and target variable (y).
- The data is further split into training (80%) and testing (20%) sets using train_test_split.

- Model Training:
- We create a LinearRegression model and fit it to the training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:

- Model Interpretation:
- New Predictions:
- We predict exam scores for new values (combinations of hours studied and practice tests).

- Visualization:
- We create two plots to visualize the results:
- A residual plot to check for any patterns in the model's errors.

**4.1.2 Polynomial Regression**

y = β₀ + β₁x + β₂x² + ε

Where:

- y is the target variable
- x is the input feature
- β₀ is the y-intercept
- β₁ and β₂ are coefficients
- ε is the error term

**Applying Polynomial Regression with Scikit-learn**

`PolynomialFeatures`

that simplifies the process of incorporating polynomial terms into our input features. This class automates the creation of higher-degree polynomial features, allowing us to effortlessly transform our linear regression model into a polynomial one.

`PolynomialFeatures`

, we can explore and capture non-linear relationships in our data without manually calculating complex polynomial terms. This feature proves particularly useful when dealing with datasets where the relationship between variables isn't strictly linear, enabling us to model more intricate patterns and potentially improve our predictive accuracy.

**Example: Polynomial Regression with Scikit-learn**

`import numpy as np`

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.preprocessing import PolynomialFeatures

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import train_test_split

from sklearn.metrics import mean_squared_error, r2_score

# Generate sample data (Hours studied vs. Exam score with a non-linear relationship)

np.random.seed(42)

X = np.random.rand(100, 1) * 10

y = 3 * X**2 + 2 * X + 5 + np.random.randn(100, 1) * 5

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Create polynomial features (degree 2)

poly = PolynomialFeatures(degree=2)

X_train_poly = poly.fit_transform(X_train)

X_test_poly = poly.transform(X_test)

# Train the polynomial regression model

model = LinearRegression()

model.fit(X_train_poly, y_train)

# Make predictions on the test set

y_pred = model.predict(X_test_poly)

# Calculate performance metrics

mse = mean_squared_error(y_test, y_pred)

r2 = r2_score(y_test, y_pred)

# Print model coefficients and performance metrics

print("Model Coefficients:")

for i, coef in enumerate(model.coef_[0]):

print(f"Degree {i}: {coef:.4f}")

print(f"Intercept: {model.intercept_[0]:.4f}")

print(f"\nMean Squared Error: {mse:.4f}")

print(f"R-squared Score: {r2:.4f}")

# Predict for new values

X_new = np.array([[6], [7], [8]])

X_new_poly = poly.transform(X_new)

y_new_pred = model.predict(X_new_poly)

print("\nPredicted exam scores for new values:")

for hours, score in zip(X_new, y_new_pred):

print(f"Hours Studied: {hours[0]:.1f}, Predicted Score: {score[0]:.2f}")

# Plot the data and the polynomial regression curve

plt.figure(figsize=(12, 6))

# Scatter plot of original data

plt.scatter(X, y, color='blue', alpha=0.5, label='Original data')

# Polynomial regression curve

X_plot = np.linspace(0, 10, 100).reshape(-1, 1)

X_plot_poly = poly.transform(X_plot)

y_plot = model.predict(X_plot_poly)

plt.plot(X_plot, y_plot, color='red', label='Polynomial regression curve')

# Scatter plot of test data

plt.scatter(X_test, y_test, color='green', alpha=0.7, label='Test data')

# Scatter plot of predictions on test data

plt.scatter(X_test, y_pred, color='orange', alpha=0.7, label='Predictions')

plt.xlabel("Hours Studied")

plt.ylabel("Exam Score")

plt.title("Polynomial Regression: Hours Studied vs. Exam Score")

plt.legend()

plt.grid(True, alpha=0.3)

plt.show()

# Residual plot

plt.figure(figsize=(10, 6))

residuals = y_test - y_pred

plt.scatter(y_pred, residuals, color='purple', alpha=0.7)

plt.xlabel("Predicted Values")

plt.ylabel("Residuals")

plt.title("Residual Plot")

plt.axhline(y=0, color='r', linestyle='--')

plt.grid(True, alpha=0.3)

plt.show()

Code Breakdown Explanation:

- Importing Libraries:
- Data Generation:
- We create a synthetic dataset with 100 samples, representing hours studied (X) and exam scores (y).

- Data Splitting:
- We split the data into training (80%) and testing (20%) sets using train_test_split.
- This allows us to evaluate the model's performance on unseen data.

- Feature Engineering:
- We use PolynomialFeatures to create polynomial terms up to degree 2.

- Model Training:
- We create a LinearRegression model and fit it to the polynomial-transformed training data.

- Model Evaluation:
- We make predictions on the test set and calculate two common performance metrics:

- Model Interpretation:
- New Predictions:
- We predict exam scores for new values of hours studied (6, 7, and 8 hours).

- Visualization:
- We create two plots to visualize the results:
- A residual plot to check for any patterns in the model's errors.