Sling Academy
Home/Rust/Implementing Linear Regression in Rust with Basic Math Operations

Implementing Linear Regression in Rust with Basic Math Operations

Last updated: January 03, 2025

Linear regression is a fundamental machine learning tool used for predictive modeling and statistical analysis. It provides insights into relationships between variables and can be a stepping stone into more complex models. Implementing linear regression from scratch in Rust not only gives us a deeper understanding of the algorithm but also acquaints us with Rust’s capabilities for numeric computation.

Understanding Linear Regression

At its core, linear regression attempts to fit a line through a set of data points such that the distance from each point to the line is minimized. Mathematically, it's represented as:

y = mx + c

Where:

  • y is the dependent variable we're trying to predict
  • m is the slope of the line
  • x is the independent variable
  • c is the y-intercept

Implementing Linear Regression from Scratch

Below is a step-by-step approach to implementing linear regression in Rust using basic math operations:

1. Setting Up the Project

Begin by creating a new Rust project:

cargo new linear_regression

Change directory into your new project:

cd linear_regression

2. Data Representation

Define your data points using tuples for easy manipulation:


fn main() {
    let data_points = vec![
        (1.0, 2.0),
        (2.0, 3.0),
        (3.0, 5.0),
        (4.0, 7.0),
        (5.0, 8.0),
        (6.0, 11.0),
    ];
    // Further computation will be done on this data
}

3. Calculating the Mean

To compute the linear regression line, we first need the means of the x and y values:


fn mean(values: &Vec) -> f64 {
    values.iter().sum::() / values.len() as f64
}

Using this function, we can calculate:


let x_vals: Vec = data_points.iter().map(|(x, _)| *x).collect();
let y_vals: Vec = data_points.iter().map(|(_, y)| *y).collect();

let x_mean = mean(&x_vals);
let y_mean = mean(&y_vals);

4. Calculating Slope (m)

The slope formula is given by:


Slope (m) = Σ[(x_i - x_mean) * (y_i - y_mean)] / Σ[(x_i - x_mean)^2]

Implementing this in Rust:


fn calculate_slope(data_points: &Vec<(f64, f64)>, x_mean: f64, y_mean: f64) -> f64 {
    let numerator: f64 = data_points.iter().map(|(x, y)| (x - x_mean) * (y - y_mean)).sum();
    let denominator: f64 = data_points.iter().map(|(x, _)| (x - x_mean).powi(2)).sum();
    numerator / denominator
}

let slope = calculate_slope(&data_points, x_mean, y_mean);

5. Calculating Intercept (c)

With the slope in hand, calculate the intercept:


let intercept = y_mean - (slope * x_mean);

6. Finalizing the Model

With the slope and intercept calculated, our model can predict new y values:


fn predict(x: f64, slope: f64, intercept: f64) -> f64 {
    slope * x + intercept
}

let predicted_y_for_new_x = predict(10.0, slope, intercept);
println!("Predicted y for x=10.0: {}", predicted_y_for_new_x);

Conclusion

Implementing linear regression from the ground up, you've combined Rust with statistical methods to understand the deeper workings of this simple yet powerful statistical tool. Rust's safety and performance assist greatly in handling such computational tasks, making it a suitable alternative for statistical computations. Continue exploring Rust for more robust machine learning applications!

Next Article: Working with Complex Numbers in Rust via External Crates

Previous Article: Calculating Variance and Standard Deviation in Rust

Series: Math and Numbers in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior