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);
}
性能建议
- 对于大型矩阵,考虑使用
ndarray
的并行特性 - 调整容差参数平衡精度和性能
- 对于稀疏矩阵,可结合其他线性代数库使用
错误处理
库提供了详细的错误类型,包括:
- 矩阵维度不匹配
- 数值计算错误
- 收敛失败等情况
注意事项
- 确保输入矩阵的维度正确
- 选择合适的容差值避免数值不稳定
- 对于病态问题考虑使用正则化
这个库为Rust开发者提供了强大而灵活的最小二乘法计算能力,特别适合机器学习、数据分析和科学计算应用场景。