#![forbid(unsafe_code)]
#![forbid(missing_docs)]
#![forbid(clippy::all)]
#![doc = include_str!("../README.md")]
use rand::Rng;
pub fn sigmoid(x: f64) -> f64 {
1.0 / (1.0 + (-x).exp())
}
pub struct LRClassifier {
pub weights: Vec<f64>,
pub learning_rate: f64,
pub lambda: f64,
}
impl LRClassifier {
pub fn new(input_size: usize, learning_rate: f64, lambda: f64) -> Self {
let mut rng = rand::thread_rng();
let weights = (0..input_size).map(|_| rng.gen_range(-1.0..1.0)).collect();
Self {
weights,
learning_rate,
lambda,
}
}
pub fn predict(&self, input: &[f64]) -> f64 {
let linear_model = input.iter().zip(&self.weights).map(|(x, w)| x * w).sum();
sigmoid(linear_model)
}
pub fn train_once(&mut self, inputs: &[Vec<f64>], outputs: &[f64]) {
for (input, &output) in inputs.iter().zip(outputs) {
let prediction = self.predict(input);
let error = prediction - output;
for (j, weight) in self.weights.iter_mut().enumerate() {
let l2r = self.lambda * *weight;
*weight -= self.learning_rate * (error * input[j] + l2r);
}
}
}
pub fn train(&mut self, inputs: &[Vec<f64>], outputs: &[f64], epochs: usize) {
for _ in 0..epochs {
self.train_once(inputs, outputs);
}
}
}