use crate::error::{StatsError, StatsResult};
use crate::regression::utils::*;
use crate::regression::RegressionResults;
use scirs2_core::ndarray::{Array1, Array2, ArrayView1};
use scirs2_core::numeric::Float;
use scirs2_linalg::lstsq;
#[allow(dead_code)]
pub fn polyfit<F>(
x: &ArrayView1<F>,
y: &ArrayView1<F>,
deg: usize,
) -> StatsResult<RegressionResults<F>>
where
F: Float
+ std::iter::Sum<F>
+ std::ops::Div<Output = F>
+ std::fmt::Debug
+ std::fmt::Display
+ 'static
+ scirs2_core::numeric::NumAssign
+ scirs2_core::numeric::One
+ scirs2_core::ndarray::ScalarOperand
+ Send
+ Sync,
{
if x.len() != y.len() {
return Err(StatsError::DimensionMismatch(format!(
"Input x has length {} but y has length {}",
x.len(),
y.len()
)));
}
let n = x.len();
let p = deg + 1;
if n <= deg {
return Err(StatsError::InvalidArgument(format!(
"Number of data points ({}) must be greater than polynomial degree ({})",
n, deg
)));
}
let mut vandermonde = Array2::<F>::zeros((n, p));
for i in 0..n {
vandermonde[[i, 0]] = F::one();
for j in 1..=deg {
vandermonde[[i, j]] = scirs2_core::numeric::Float::powi(x[i], j as i32);
}
}
let coefficients = match lstsq(&vandermonde.view(), y, None) {
Ok(result) => result.x,
Err(e) => {
return Err(StatsError::ComputationError(format!(
"Least squares computation failed: {:?}",
e
)));
}
};
let fitted_values = vandermonde.dot(&coefficients);
let residuals = y.to_owned() - &fitted_values;
let df_model = p - 1;
let df_residuals = n - p;
let (_y_mean, ss_total, ss_residual, ss_explained) =
calculate_sum_of_squares(y, &residuals.view());
let r_squared = ss_explained / ss_total;
let adj_r_squared = F::one()
- (F::one() - r_squared) * F::from(n - 1).expect("Operation failed")
/ F::from(df_residuals).expect("Operation failed");
let mse = ss_residual / F::from(df_residuals).expect("Operation failed");
let residual_std_error = scirs2_core::numeric::Float::sqrt(mse);
let std_errors =
match calculate_std_errors(&vandermonde.view(), &residuals.view(), df_residuals) {
Ok(se) => se,
Err(_) => Array1::<F>::zeros(p),
};
let t_values = calculate_t_values(&coefficients, &std_errors);
let p_values = Array1::<F>::zeros(p);
let mut conf_intervals = Array2::<F>::zeros((p, 2));
for i in 0..p {
conf_intervals[[i, 0]] = coefficients[i] - std_errors[i];
conf_intervals[[i, 1]] = coefficients[i] + std_errors[i];
}
let f_statistic = if df_model > 0 && df_residuals > 0 {
(ss_explained / F::from(df_model).expect("Operation failed"))
/ (ss_residual / F::from(df_residuals).expect("Operation failed"))
} else {
F::infinity()
};
let f_p_value = F::zero();
Ok(RegressionResults {
coefficients,
std_errors,
t_values,
p_values,
conf_intervals,
r_squared,
adj_r_squared,
f_statistic,
f_p_value,
residual_std_error,
df_residuals,
residuals,
fitted_values,
inlier_mask: vec![true; n], })
}