use std;
use rand::{thread_rng, Rng};
use rand::distributions::Uniform;
use csv;
use FeedForward;
pub trait Extractable {
fn rand(&self) -> (&Vec<f64>, &Vec<f64>);
fn get(&self, i: usize) -> (&Vec<f64>, &Vec<f64>);
fn len(&self) -> usize;
}
#[derive(Debug)]
pub struct DataSet{
x: Vec<Vec<f64>>,
y: Vec<Vec<f64>>,
tx: Vec<Vec<f64>>,
ty: Vec<Vec<f64>>,
}
impl DataSet {
pub fn new() -> DataSet{
return DataSet {
x: vec![],
y: vec![],
tx: vec![],
ty: vec![],
}
}
pub fn from_csv(file_path: &str) -> Result<DataSet, Box<dyn std::error::Error>> {
let mut file = csv::ReaderBuilder::new()
.has_headers(false)
.from_path(file_path)?;
let mut data_set = DataSet::new();
let mut is_x: bool;
for row in file.records(){
let records = row?;
let mut x: Vec<f64> = Vec::new();
let mut y: Vec<f64> = Vec::new();
is_x = true;
for i in 0..records.len(){
if records.get(i).unwrap() == "-"{
is_x = false;
continue;
} else if let Some(v) = records.get(i){
if is_x {
x.push(v.parse()?);
} else {
y.push(v.parse()?);
}
}
}
data_set.push(&x, &y);
}
Ok(data_set)
}
pub fn sum(&self) -> (Vec<f64>, Vec<f64>){
let mut sum_x = vec![0.0; self.x[0].len()];
let mut sum_y = vec![0.0; self.y[0].len()];
for i in 0..self.x.len(){
for j in 0..self.x[i].len(){
sum_x[j] += self.x[i][j];
}
}
for i in 0..self.y.len(){
for j in 0..self.y[i].len(){
sum_y[j] += self.y[i][j];
}
}
(sum_x, sum_y)
}
pub fn mean(&self) -> (Vec<f64>, Vec<f64>){
let (sum_x, sum_y) = self.sum();
let mut mean_x = sum_x.clone().to_vec();
for i in 0..self.x[0].len(){
mean_x[i] /= self.x.len() as f64;
}
let mut mean_y = sum_y.clone().to_vec();
for i in 0..self.y[0].len(){
mean_y[i] /= self.y.len() as f64;
}
(mean_x, mean_y)
}
pub fn round(&mut self, precision: u32){
let pow = 10f64.powi(precision as i32);
for i in 0..self.x.len(){
for j in 0..self.x[i].len(){
self.x[i][j] = (self.x[i][j] * pow).round() / pow;
}
}
for i in 0..self.y.len(){
for j in 0..self.y[i].len(){
self.y[i][j] = (self.y[i][j] * pow).round() / pow;
}
}
}
pub fn push(&mut self, x: &[f64], y: &[f64]){
self.x.push(x.to_vec());
self.y.push(y.to_vec());
}
pub fn divide(&mut self, proportion: f64){
for i in 0..self.tx.len(){
self.x.push(self.tx[i].clone());
self.y.push(self.ty[i].clone());
}
self.tx = vec![];
self.ty = vec![];
let amount = (self.x.len() as f64 * proportion) as i32;
for _ in 0..amount{
let i = self.rand_index();
self.tx.push(self.x[i].clone());
self.ty.push(self.y[i].clone());
self.remove(i);
}
}
pub fn remove(&mut self, i: usize){
self.x.remove(i);
self.y.remove(i);
}
fn rand_index(&self) -> usize {
let mut rng = thread_rng();
rng.sample(Uniform::new(0, self.y.len()))
}
pub fn cv(&self, nn: &mut FeedForward) -> f64 {
let mut error: Vec<f64> = vec![0.0; self.y[0].len()];
for i in 0..self.ty.len(){
let res = nn.calc(&self.tx[i]);
for j in 0..self.ty[i].len(){
error[j] += (self.ty[i][j] - res[j]).abs();
}
}
let len = self.ty.len() as f64;
let _ = error.iter().map(|x| x / len).collect::<Vec<f64>>();
error.iter().sum::<f64>() / len
}
}
impl Extractable for DataSet{
fn rand(&self) -> (&Vec<f64>, &Vec<f64>){
let mut rnd_range = thread_rng();
let k = rnd_range.sample(Uniform::new(0, self.y.len()));
(&self.x[k], &self.y[k])
}
fn get(&self, i: usize) -> (&Vec<f64>, &Vec<f64>){
(&self.x[i], &self.y[i])
}
fn len(&self) -> usize {
self.y.len()
}
}