use std::convert::From;
use std::fmt;
use std::iter::{FromIterator, Sum};
use std::marker::{Send, Sync};
use std::ops::{Index, IndexMut, Range};
use std::str::FromStr;
use std::vec::IntoIter;
use serde::{Deserialize, Serialize};
use itertools::Itertools;
use num::*;
use rayon::prelude::*;
use stats;
pub mod overloaders;
pub mod rolling;
pub mod series_groupby;
pub mod variants;
pub use self::rolling::*;
pub use self::series_groupby::*;
pub use self::variants::*;
use crate::funcs;
use crate::prelude::*;
impl_series_into_iter!(String);
impl_series_into_iter!(f64);
impl_series_into_iter!(i64);
impl_series_into_iter!(f32);
impl_series_into_iter!(i32);
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, PartialOrd)]
pub struct Series<T>
where
T: BlackJackData,
{
pub name: Option<String>,
pub values: Vec<T>,
dtype: Option<DType>,
}
impl<I> Default for Series<I>
where
I: PartialOrd + PartialEq + BlackJackData,
{
fn default() -> Self {
Series::from_vec(vec![])
}
}
impl<T> Series<T>
where
T: BlackJackData,
{
pub fn arange(start: T, stop: T) -> Self
where
T: Integer + BlackJackData + ToPrimitive,
Range<T>: Iterator,
Vec<T>: FromIterator<<Range<T> as Iterator>::Item>,
{
let dtype = Some(start.dtype());
let values: Vec<T> = (start..stop).collect();
Series {
name: None,
dtype,
values,
}
}
pub fn drop_positions<I>(&mut self, positions: I) -> ()
where
I: IntoIterator<Item = usize>,
{
let positions = positions.into_iter().collect::<Vec<usize>>();
self.values = self
.values
.iter()
.enumerate()
.filter_map(|(position, val)| {
if positions.contains(&position) {
None
} else {
Some(val.clone())
}
})
.collect::<Vec<T>>();
}
pub fn iloc<'b, I>(&self, idx_vals: I) -> Vec<&T>
where
I: IntoIterator<Item = &'b usize>,
{
idx_vals
.into_iter()
.map(|idx_val| &self.values[*idx_val])
.collect::<Vec<&T>>()
}
pub fn rolling(&self, window: usize) -> Rolling<T>
where
T: Send + Sync,
{
Rolling::new(window, &self)
}
pub fn isna<'a>(&'a self) -> impl Iterator<Item = bool> + 'a
where
T: Float,
{
self.values.iter().map(|v| v.is_nan())
}
pub fn all<F>(&self, condition: F) -> bool
where
for<'r> F: Fn(&'r T) -> bool,
{
self.values.iter().all(condition)
}
pub fn all_equal(&self) -> bool
where
T: PartialEq,
{
self.values.iter().all_equal()
}
pub fn any<F>(&self, condition: F) -> bool
where
for<'r> F: FnMut(&'r &T) -> bool,
{
let first_match = self.values.iter().find(condition);
match first_match {
Some(_) => true,
None => false,
}
}
pub fn cartesian_product<O>(&self, other: &Series<O>) -> (Series<T>, Series<O>)
where
O: BlackJackData,
{
let mut left = vec![];
let mut right = vec![];
let _ = self
.values
.clone()
.into_iter()
.cartesian_product(other.values.clone().into_iter())
.map(|(l, r)| {
left.push(l);
right.push(r);
})
.collect::<Vec<()>>();
(Series::from_vec(left), Series::from_vec(right))
}
pub fn positions<'a, F>(&'a self, condition: F) -> impl Iterator<Item = usize> + 'a
where
F: 'a + Fn(&T) -> bool,
{
self.values.iter().positions(condition)
}
pub fn map_par<B, F>(self, func: F) -> Series<B>
where
B: BlackJackData,
F: Fn(T) -> B + Send + Sync,
{
let new_data = self.values.into_par_iter().map(func).collect();
Series::from_vec(new_data)
}
pub fn map<B, F>(self, func: F) -> Series<B>
where
B: BlackJackData,
F: Fn(T) -> B,
{
let new_data = self.values.into_iter().map(func).collect();
Series::from_vec(new_data)
}
pub fn astype<A>(&self) -> Result<Series<A>, &'static str>
where
A: BlackJackData + FromStr,
{
let values = self
.values
.clone()
.into_iter()
.map(|v| v.to_string())
.map(|v| v.parse::<A>().map_err(|_| "Cannot cast into type"))
.collect::<Result<Vec<A>, _>>()?;
let series = Series {
name: self.name.clone(),
dtype: Some(values[0].dtype()),
values,
};
Ok(series)
}
pub fn into_type<A>(self) -> Result<Series<A>, &'static str>
where
A: BlackJackData + FromStr,
{
let values = self
.values
.into_iter()
.map(|v| v.to_string())
.map(|v| v.parse::<A>().map_err(|_| "Cannot cast into type"))
.collect::<Result<Vec<A>, _>>()?;
let series = Series {
name: self.name.clone(),
dtype: Some(values[0].dtype()),
values,
};
Ok(series)
}
pub fn unique(&self) -> Series<T>
where
T: PartialOrd + Copy,
{
let mut unique: Vec<T> = vec![];
let mut values = self.values.clone();
values.sort_by(|a, b| a.partial_cmp(b).unwrap());
for val in values {
if unique.len() > 0 {
if val == unique[unique.len() - 1] {
continue;
} else {
unique.push(val)
}
} else {
unique.push(val)
}
}
Series::from_vec(unique)
}
pub fn from_vec(vec: Vec<T>) -> Self {
let dtype = if vec.len() == 0 {
None
} else {
Some(vec[0].dtype())
};
Series {
name: None,
dtype,
values: vec,
}
}
pub fn into_vec(self) -> Vec<T> {
self.values
}
pub fn set_name(&mut self, name: &str) -> () {
self.name = Some(name.to_string());
}
pub fn name(&self) -> Option<String> {
match self.name {
Some(ref name) => Some(name.clone()),
None => None,
}
}
pub fn mode(&self) -> Result<Self, BlackJackError>
where
T: BlackJackData + PartialOrd + Copy + ToPrimitive,
{
if self.len() == 0 {
return Err(BlackJackError::from(
"Cannot compute mode of an empty series!",
));
}
let modes = stats::modes(self.values.iter().map(|v| *v));
let modes = Series::from_vec(modes);
Ok(modes)
}
pub fn var(&self, ddof: f64) -> Result<f64, BlackJackError>
where
T: ToPrimitive + Num,
{
if self.len() == 0 {
return Err(BlackJackError::ValueError(
"Cannot compute variance of an empty series!".to_owned(),
));
}
funcs::variance(self.values.as_slice(), ddof)
.ok_or_else(|| BlackJackError::from("Failed to calculate variance of series."))
}
pub fn std(&self, ddof: f64) -> Result<f64, BlackJackError>
where
T: BlackJackData + ToPrimitive + Copy + Num,
{
if self.len() == 0 {
return Err(BlackJackError::ValueError(
"Cannot compute standard deviation of an empty series!".to_owned(),
));
}
funcs::std(self.values.as_slice(), ddof)
.ok_or_else(|| BlackJackError::from("Failed to calculate stddev of series."))
}
pub fn sum(&self) -> T
where
T: Num + Copy + Sum,
{
funcs::sum(self.values.as_slice())
}
pub fn mean(&self) -> Result<f64, BlackJackError>
where
T: ToPrimitive + Copy + Num + Sum,
{
funcs::mean(self.values.as_slice())
.ok_or_else(|| BlackJackError::from("Failed to calculate mean!"))
}
pub fn quantile(&self, quantile: f64) -> Result<f64, BlackJackError>
where
T: ToPrimitive + BlackJackData,
{
use rgsl::statistics::quantile_from_sorted_data;
use std::cmp::Ordering;
let mut vec = self
.clone()
.into_vec()
.into_iter()
.map(|v| v.to_f64().unwrap())
.collect::<Vec<f64>>();
vec.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
let qtl = quantile_from_sorted_data(&vec[..], 1, vec.len(), quantile);
Ok(qtl)
}
pub fn median(&self) -> Result<f64, BlackJackError>
where
T: ToPrimitive + Copy + PartialOrd,
{
if self.len() == 0 {
return Err(BlackJackError::from(
"Cannot calculate median of an empty series.",
));
}
stats::median(self.values.iter().map(|v| v.to_f64().unwrap())).ok_or_else(|| {
BlackJackError::from(
r#"Unable to calculate median, please create an issue!
as this wasn't expected to ever happen on a non-empty
series. :("#,
)
})
}
pub fn min(&self) -> Result<T, BlackJackError>
where
T: Num + PartialOrd + BlackJackData + Copy,
{
funcs::min(self.values.as_slice())
.map(|v| *v)
.ok_or_else(|| BlackJackError::from("Failed to calculate min of series."))
}
pub fn max(&self) -> Result<T, BlackJackError>
where
T: Num + PartialOrd + BlackJackData + Copy,
{
funcs::max(self.values.as_slice())
.map(|v| *v)
.ok_or_else(|| BlackJackError::from("Failed to calculate max of series."))
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn dtype(&self) -> Option<DType> {
self.dtype.clone()
}
pub fn append<V: Into<T>>(&mut self, val: V) -> () {
let v = val.into();
self.values.push(v);
}
pub fn into_raw(self) -> *mut Self {
Box::into_raw(Box::new(self))
}
pub fn from_raw(ptr: *mut Self) -> Self {
unsafe { *Box::from_raw(ptr) }
}
pub fn groupby(&self, keys: &Series<T>) -> SeriesGroupBy<T>
where
T: ToPrimitive,
{
use indexmap::IndexMap;
let values = self.values.clone();
let mut map: IndexMap<String, Vec<T>> = IndexMap::new();
for (k, v) in keys.values.iter().zip(values.iter()) {
let key = k.to_string();
let mr = map.entry(key).or_insert(vec![]);
mr.push(v.clone());
}
let groups = map
.iter()
.map(|(name, values)| {
let mut series = Series::from_vec(values.clone());
series.set_name(name.as_str());
series
})
.collect();
SeriesGroupBy::new(groups)
}
pub fn find<F: Fn(&T) -> bool>(&self, condition: F) -> Vec<usize> {
self.values
.iter()
.enumerate()
.filter(|(_idx, val)| condition(val))
.map(|(idx, _val)| idx)
.collect()
}
}
impl<T> From<std::ops::Range<T>> for Series<T>
where
T: BlackJackData,
std::ops::Range<T>: Iterator,
Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
{
fn from(range: std::ops::Range<T>) -> Series<T> {
let vec = range.collect();
Series::from_vec(vec)
}
}
impl<T> Index<usize> for Series<T>
where
T: BlackJackData,
{
type Output = T;
fn index(&self, idx: usize) -> &T {
&self.values[idx]
}
}
impl<T> Index<Range<usize>> for Series<T>
where
T: BlackJackData,
{
type Output = [T];
fn index(&self, idx: Range<usize>) -> &[T] {
&self.values[idx]
}
}
impl<T: BlackJackData> IndexMut<usize> for Series<T> {
fn index_mut(&mut self, idx: usize) -> &mut T {
&mut self.values[idx]
}
}
impl<T> fmt::Display for Series<T>
where
T: BlackJackData,
String: From<T>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use prettytable::{Cell, Row, Table};
let mut table = Table::new();
table.add_row(Row::new(vec![Cell::new(
&self.name().unwrap_or("<NA>".to_string()),
)]));
let _ = self
.values
.iter()
.map(|v| {
let v: String = v.clone().into();
table.add_row(Row::new(vec![Cell::new(&format!("{}", v))]));
})
.collect::<Vec<()>>();
write!(f, "{}\n", table)
}
}