use crate::core::RegressionOutput;
use crate::error::Result;
use crate::feature_importance::{
permutation_importance_elastic_net as core_permutation_importance_elastic_net,
permutation_importance_lasso as core_permutation_importance_lasso,
permutation_importance_loess as core_permutation_importance_loess,
permutation_importance_ols_named,
permutation_importance_ridge as core_permutation_importance_ridge,
shap_values_elastic_net as core_shap_values_elastic_net,
shap_values_lasso as core_shap_values_lasso,
shap_values_linear_named,
shap_values_polynomial as core_shap_values_polynomial,
shap_values_ridge as core_shap_values_ridge,
standardized_coefficients_named,
vif_ranking as core_vif_ranking, PermutationImportanceOptions, PermutationImportanceOutput,
ShapOutput, StandardizedCoefficientsOutput, VifRankingOutput,
};
use crate::polynomial::PolynomialFit;
use crate::regularized::{ElasticNetFit, LassoFit, RidgeFit};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn standardized_coefficients(
x_json: &str,
coefficients_json: &str,
variable_names_json: &str,
y_std: f64,
) -> String {
let result: Result<StandardizedCoefficientsOutput> = (|| {
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let coefficients: Vec<f64> = serde_json::from_str(coefficients_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid coefficients_json: {}", e)))?;
let variable_names: Vec<String> = serde_json::from_str(variable_names_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid variable_names_json: {}", e)))?;
standardized_coefficients_named(&coefficients, &x_vars, &variable_names, y_std)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn shap_values_linear(
x_json: &str,
coefficients_json: &str,
variable_names_json: &str,
) -> String {
let result: Result<ShapOutput> = (|| {
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let coefficients: Vec<f64> = serde_json::from_str(coefficients_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid coefficients_json: {}", e)))?;
let variable_names: Vec<String> = serde_json::from_str(variable_names_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid variable_names_json: {}", e)))?;
shap_values_linear_named(&x_vars, &coefficients, &variable_names)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn permutation_importance_ols(
y_json: &str,
x_json: &str,
fit_json: &str,
n_permutations: usize,
seed: u64,
) -> String {
let result: Result<PermutationImportanceOutput> = (|| {
let y: Vec<f64> = serde_json::from_str(y_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid y_json: {}", e)))?;
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: RegressionOutput = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
let variable_names: Vec<String> = (0..x_vars.len())
.map(|i| format!("X{}", i + 1))
.collect();
let options = PermutationImportanceOptions {
n_permutations,
seed: if seed == 0 { None } else { Some(seed) },
compute_intervals: false,
interval_confidence: 0.95,
};
permutation_importance_ols_named(&y, &x_vars, &fit, &options, &variable_names)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn vif_ranking(vif_json: &str) -> String {
let result: Result<VifRankingOutput> = (|| {
let vif_results: Vec<crate::core::VifResult> = serde_json::from_str(vif_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid vif_json: {}", e)))?;
Ok(core_vif_ranking(&vif_results))
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn feature_importance_ols(
y_json: &str,
x_json: &str,
variable_names_json: &str,
y_std: f64,
n_permutations: usize,
seed: u64,
) -> String {
use serde_json::json;
let result: Result<serde_json::Value> = (|| {
let y: Vec<f64> = serde_json::from_str(y_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid y_json: {}", e)))?;
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let variable_names: Vec<String> = serde_json::from_str(variable_names_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid variable_names_json: {}", e)))?;
let names_with_intercept = {
let mut names = vec!["Intercept".to_string()];
names.extend(variable_names.clone());
names
};
let fit = crate::core::ols_regression(&y, &x_vars, &names_with_intercept)?;
let std_coefs = standardized_coefficients_named(&fit.coefficients, &x_vars, &variable_names, y_std)?;
let shap = shap_values_linear_named(&x_vars, &fit.coefficients, &variable_names)?;
let perm_options = PermutationImportanceOptions {
n_permutations,
seed: if seed == 0 { None } else { Some(seed) },
compute_intervals: false,
interval_confidence: 0.95,
};
let perm_importance = permutation_importance_ols_named(&y, &x_vars, &fit, &perm_options, &variable_names)?;
let vif_rank = core_vif_ranking(&fit.vif);
Ok(json!({
"standardized_coefficients": std_coefs,
"shap": shap,
"permutation_importance": perm_importance,
"vif_ranking": vif_rank,
}))
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn shap_values_ridge(
x_json: &str,
fit_json: &str,
) -> String {
let result: Result<ShapOutput> = (|| {
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: RidgeFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
core_shap_values_ridge(&x_vars, &fit)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn shap_values_lasso(
x_json: &str,
fit_json: &str,
) -> String {
let result: Result<ShapOutput> = (|| {
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: LassoFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
core_shap_values_lasso(&x_vars, &fit)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn shap_values_elastic_net(
x_json: &str,
fit_json: &str,
) -> String {
let result: Result<ShapOutput> = (|| {
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: ElasticNetFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
core_shap_values_elastic_net(&x_vars, &fit)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn shap_values_polynomial(
x_json: &str,
fit_json: &str,
) -> String {
let result: Result<ShapOutput> = (|| {
let x: Vec<f64> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: PolynomialFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
core_shap_values_polynomial(&x, &fit)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn permutation_importance_ridge(
y_json: &str,
x_json: &str,
fit_json: &str,
n_permutations: usize,
seed: u64,
compute_intervals: bool,
interval_confidence: f64,
) -> String {
let result: Result<PermutationImportanceOutput> = (|| {
let y: Vec<f64> = serde_json::from_str(y_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid y_json: {}", e)))?;
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: RidgeFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
let options = PermutationImportanceOptions {
n_permutations,
seed: if seed == 0 { None } else { Some(seed) },
compute_intervals,
interval_confidence,
};
core_permutation_importance_ridge(&y, &x_vars, &fit, &options)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn permutation_importance_lasso(
y_json: &str,
x_json: &str,
fit_json: &str,
n_permutations: usize,
seed: u64,
compute_intervals: bool,
interval_confidence: f64,
) -> String {
let result: Result<PermutationImportanceOutput> = (|| {
let y: Vec<f64> = serde_json::from_str(y_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid y_json: {}", e)))?;
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: LassoFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
let options = PermutationImportanceOptions {
n_permutations,
seed: if seed == 0 { None } else { Some(seed) },
compute_intervals,
interval_confidence,
};
core_permutation_importance_lasso(&y, &x_vars, &fit, &options)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn permutation_importance_elastic_net(
y_json: &str,
x_json: &str,
fit_json: &str,
n_permutations: usize,
seed: u64,
compute_intervals: bool,
interval_confidence: f64,
) -> String {
let result: Result<PermutationImportanceOutput> = (|| {
let y: Vec<f64> = serde_json::from_str(y_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid y_json: {}", e)))?;
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let fit: ElasticNetFit = serde_json::from_str(fit_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid fit_json: {}", e)))?;
let options = PermutationImportanceOptions {
n_permutations,
seed: if seed == 0 { None } else { Some(seed) },
compute_intervals,
interval_confidence,
};
core_permutation_importance_elastic_net(&y, &x_vars, &fit, &options)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}
#[wasm_bindgen]
pub fn permutation_importance_loess(
y_json: &str,
x_json: &str,
span: f64,
degree: usize,
n_permutations: usize,
seed: u64,
) -> String {
let result: Result<PermutationImportanceOutput> = (|| {
let y: Vec<f64> = serde_json::from_str(y_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid y_json: {}", e)))?;
let x_vars: Vec<Vec<f64>> = serde_json::from_str(x_json)
.map_err(|e| crate::error::Error::InvalidInput(format!("Invalid x_json: {}", e)))?;
let options = PermutationImportanceOptions {
n_permutations,
seed: if seed == 0 { None } else { Some(seed) },
compute_intervals: false,
interval_confidence: 0.95,
};
core_permutation_importance_loess(&y, &x_vars, span, degree, &options)
})();
match result {
Ok(output) => serde_json::to_string(&output).unwrap_or_else(|_| crate::error::error_json("Serialization failed")),
Err(e) => crate::error::error_json(&e.to_string()),
}
}