Rust最小二乘法计算库lstsq的使用,高效实现线性回归与矩阵方程求解

Rust最小二乘法计算库lstsq的使用,高效实现线性回归与矩阵方程求解

关于

该crate实现了线性矩阵方程的最小二乘解。

特点:

  • 使用nalgebra crate的线性代数和类型
  • 与Python库函数numpy.linalg.lstsq最大兼容性
  • 不需要标准库(禁用默认功能以禁用std的使用)且没有堆分配。换句话说,这可以在没有操作系统的裸机微控制器上运行。

测试

单元测试

运行单元测试:

cargo test

测试no_std

由于thumbv7em-none-eabihf目标没有std可用,我们可以为其构建以检查我们的crate不会无意中引入std。单元测试需要std,因此无法在no_std平台上运行。如果存在std依赖项,以下操作将失败:

# 使用"rustup target add thumbv7em-none-eabihf"安装目标
cargo build --no-default-features --target thumbv7em-none-eabihf

安装

在项目目录中运行以下Cargo命令:

cargo add lstsq

或者将以下行添加到Cargo.toml中:

lstsq = "0.7.0"

完整示例代码

use nalgebra::{DMatrix, DVector};
use lstsq::lstsq;

fn main() {
    // 创建示例数据:y = 2*x + 3 + 噪声
    let x_data = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
    let y_data = DVector::from_vec(vec![5.1, 7.2, 9.3, 11.2, 13.1]);
    
    // 构建设计矩阵(对于线性回归 y = a*x + b)
    let mut a_matrix = DMatrix::zeros(x_data.len(), 2);
    for i in 0..x_data.len() {
        a_matrix[(i, 0)] = x_data[i];  // x项
        a_matrix[(i, 1)] = 1.0;        // 截距项
    }
    
    // 使用lstsq求解最小二乘问题
    let result = lstsq(&a_matrix, &y_data, 1e-10).unwrap();
    
    // 提取解向量(系数)
    let coefficients = result.solution;
    
    println!("线性回归结果:");
    println!("斜率 (a) = {:.4}", coefficients[0]);
    println!("截距 (b) = {:.4}", coefficients[1]);
    
    // 计算拟合值
    let y_pred = &a_matrix * &coefficients;
    println!("\n预测值: {:?}", y_pred);
    
    // 计算残差
    let residuals = &y_data - &y_pred;
    println!("残差: {:?}", residuals);
    
    // 计算残差平方和
    let rss: f64 = residuals.iter().map(|x| x * x).sum();
    println!("残差平方和: {:.4}", rss);
}

矩阵方程求解示例

use nalgebra::{DMatrix, DVector};
use lstsq::lstsq;

fn main() {
    // 求解矩阵方程 A * x = b
    let a = DMatrix::from_row_slice(3, 2, &[
        1.0, 2.0,
        3.0, 4.0,
        5.0, 6.0
    ]);
    
    let b = DVector::from_vec(vec![6.0, 13.0, 20.0]);
    
    // 使用最小二乘法求解
    let result = lstsq(&a, &b, 1e-10).unwrap();
    
    println!("矩阵方程 A * x = b 的最小二乘解:");
    println!("x = {:?}", result.solution);
    println!("残差: {:?}", result.residuals);
    println!("秩: {}", result.rank);
    println!("奇异值: {:?}", result.singular_values);
}

多变量线性回归示例

use nalgebra::{DMatrix, DVector};
use lstsq::lstsq;

fn main() {
    // 多变量线性回归示例:y = 1.5*x1 + 2.0*x2 + 0.5*x3 + 噪声
    let x1 = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
    let x2 = DVector::from_vec(vec![2.0, 3.0, 1.0, 4.0, 2.0]);
    let x3 = DVector::from_vec(vec![1.0, 1.0, 2.0, 2.0, 3.0]);
    let y = DVector::from_vec(vec![6.0, 10.0, 10.5, 16.0, 15.5]);
    
    // 构建设计矩阵
    let n = x1.len();
    let mut design_matrix = DMatrix::zeros(n, 4);
    
    for i in 0..n {
        design_matrix[(i, 0)] = x1[i];
        design_matrix[(i, 1)] = x2[i];
        design_matrix[(i, 2)] = x3[i];
        design_matrix[(i, 3)] = 1.0; // 截距项
    }
    
    // 求解最小二乘问题
    let result = lstsq(&design_matrix, &y, 1e-10).unwrap();
    
    println!("多变量线性回归系数:");
    println!("x1 系数: {:.4}", result.solution[0]);
    println!("x2 系数: {:.4}", result.solution[1]);
    println!("x3 系数: {:.4}", result.solution[2]);
    println!("截距: {:.4}", result.solution[3]);
}

这些示例展示了如何使用lstsq库进行线性回归和矩阵方程求解。该库提供了与numpy.linalg.lstsq类似的功能,同时保持了Rust的性能优势和无堆分配的特性。


1 回复

Rust最小二乘法计算库lstsq使用指南

介绍

lstsq是一个专门用于最小二乘法计算的Rust库,主要用于解决线性回归问题和矩阵方程求解。该库提供了高效的数值计算实现,特别适合处理大规模数据集和数值精度要求较高的科学计算场景。

主要功能

  • 线性最小二乘问题求解
  • 矩阵方程 AX = B 的求解
  • 支持多种矩阵分解方法
  • 提供正则化选项防止过拟合

安装方法

在Cargo.toml中添加依赖:

[dependencies]
lstsq = "0.3.0"
ndarray = "0.15"

基本使用方法

示例1:简单线性回归

use ndarray::{array, Array2};
use lstsq::lstsq;

fn main() {
    // 创建样本数据
    let a: Array2<f64> = array![
        [1.0, 1.0],
        [1.0, 2.0],
        [1.0, 3.0],
        [1.0, 4.0]
    ];
    
    let b: Array2<f64> = array![[6.0], [5.0], [7.0], [10.0]];
    
    // 求解最小二乘问题
    let result = lstsq(&a, &b, 1e-10).unwrap();
    
    println!("系数: {:?}", result.solution);
    println!("残差: {:?}", result.residuals);
}

示例2:多元线性回归

use ndarray::{array, Array2};
use lstsq::lstsq;

fn main() {
    // 多元特征数据
    let features: Array2<f64> = array![
        [1.0, 2.0, 1.0],
        [1.0, 3.0, 2.0],
        [1.0, 4.0, 1.0],
        [1.0, 5.0, 3.0]
    ];
    
    let target: Array2<f64> = array![[8.0], [13.0], [10.0], [18.0]];
    
    let result = lstsq(&features, &target, 1e-12).unwrap();
    
    println!("回归系数: {:?}", result.solution);
    println!("拟合优度: {}", 1.0 - result.residuals.unwrap()[0]);
}

示例3:带正则化的岭回归

use ndarray::{array, Array2};
use lstsq::lstsq_reg;

fn main() {
    let a: Array2<f64> = array![
        [1.0, 2.0],
        [1.0, 3.0],
        [1.0, 4.0]
    ];
    
    let b: Array2<f64> = array![[3.0], [5.0], [7.0]];
    
    // 使用L2正则化(岭回归)
    let lambda = 0.1;
    let result = lstsq_reg(&a, &b, lambda, 1e-10).unwrap();
    
    println!("正则化系数: {:?}", result.solution);
}

高级功能

处理病态矩阵

use ndarray::{array, Array2};
use lstsq::{lstsq, LstsqOptions};

fn main() {
    let a: Array2<f64> = array![
        [1.0, 2.0],
        [1.0, 2.000001]  // 近似线性相关的列
    ];
    
    let b: Array2<f64> = array![[3.0], [3.000001]];
    
    let options = LstsqOptions::new()
        .tol(1e-12)
        .cond(1e-10);
    
    let result = lstsq(&a, &b, options).unwrap();
    println!("稳定解: {:?}", result.solution);
}

完整示例demo

use ndarray::{array, Array2};
use lstsq::{lstsq, lstsq_reg, LstsqOptions};

fn main() {
    println!("=== 简单线性回归示例 ===");
    simple_linear_regression();
    
    println!("\n=== 多元线性回归示例 ===");
    multiple_linear_regression();
    
    println!("\n=== 岭回归示例 ===");
    ridge_regression();
    
    println!("\n=== 病态矩阵处理示例 ===");
    ill_conditioned_matrix();
}

// 简单线性回归
fn simple_linear_regression() {
    // 创建样本数据:y = 2x + 3 + 噪声
    let a: Array2<f64> = array![
        [1.0, 1.0],  // 截距项 + 特征值
        [1.0, 2.0],
        [1.0, 3.0],
        [1.0, 4.0]
    ];
    
    let b: Array2<f64> = array![[6.0], [5.0], [7.0], [10.0]];
    
    // 求解最小二乘问题
    let result = lstsq(&a, &b, 1e-10).unwrap();
    
    println!("系数: {:?}", result.solution);
    println!("残差: {:?}", result.residuals);
}

// 多元线性回归
fn multiple_linear_regression() {
    // 多元特征数据:y = 2x1 + 3x2 + 1 + 噪声
    let features: Array2<f64> = array![
        [1.0, 2.0, 1.0],  // 截距项 + 两个特征
        [1.0, 3.0, 2.0],
        [1.0, 4.0, 1.0],
        [1.0, 5.0, 3.0]
    ];
    
    let target: Array2<f64> = array![[8.0], [13.0], [10.0], [18.0]];
    
    let result = lstsq(&features, &target, 1e-12).unwrap();
    
    println!("回归系数: {:?}", result.solution);
    if let Some(residuals) = result.residuals {
        println!("拟合优度: {}", 1.0 - residuals[0]);
    }
}

// 岭回归(L2正则化)
fn ridge_regression() {
    let a: Array2<f64> = array![
        [1.0, 2.0],
        [1.0, 3.0],
        [1.0, 4.0]
    ];
    
    let b: Array2<f64> = array![[3.0], [5.0], [7.0]];
    
    // 使用L2正则化(岭回归),lambda=0.1
    let lambda = 0.1;
    let result = lstsq_reg(&a, &b, lambda, 1e-10).unwrap();
    
    println!("正则化系数: {:?}", result.solution);
}

// 处理病态矩阵
fn ill_conditioned_matrix() {
    // 创建近似线性相关的矩阵(病态矩阵)
    let a: Array2<f64> = array![
        [1.0, 2.0],
        [1.0, 2.000001]  // 第二列近似线性相关
    ];
    
    let b: Array2<f64> = array![[3.0], [3.000001]];
    
    // 使用高级选项处理病态矩阵
    let options = LstsqOptions::new()
        .tol(1e-12)    // 设置容差
        .cond(1e-10);  // 设置条件数限制
    
    let result = lstsq(&a, &b, options).unwrap();
    println!("稳定解: {:?}", result.solution);
}

性能建议

  1. 对于大型矩阵,考虑使用ndarray的并行特性
  2. 调整容差参数平衡精度和性能
  3. 对于稀疏矩阵,可结合其他线性代数库使用

错误处理

库提供了详细的错误类型,包括:

  • 矩阵维度不匹配
  • 数值计算错误
  • 收敛失败等情况

注意事项

  • 确保输入矩阵的维度正确
  • 选择合适的容差值避免数值不稳定
  • 对于病态问题考虑使用正则化

这个库为Rust开发者提供了强大而灵活的最小二乘法计算能力,特别适合机器学习、数据分析和科学计算应用场景。

回到顶部