diff --git a/base/src/functions/mod.rs b/base/src/functions/mod.rs index af80adc..56f9ad1 100644 --- a/base/src/functions/mod.rs +++ b/base/src/functions/mod.rs @@ -814,6 +814,60 @@ impl Function { Function::BetaDist => "_xlfn.BETA.DIST".to_string(), Function::BetaInv => "_xlfn.BETA.INV".to_string(), + Function::BinomDist => "_xlfn.BINOM.DIST".to_string(), + Function::BinomDistRange => "_xlfn.BINOM.DIST.RANGE".to_string(), + Function::BinomInv => "_xlfn.BINOM.INV".to_string(), + Function::NegbinomDist => "_xlfn.NEGBINOM.DIST".to_string(), + + Function::ChisqDist => "_xlfn.CHISQ.DIST".to_string(), + Function::ChisqDistRT => "_xlfn.CHISQ.DIST.RT".to_string(), + Function::ChisqInv => "_xlfn.CHISQ.INV".to_string(), + Function::ChisqInvRT => "_xlfn.CHISQ.INV.RT".to_string(), + Function::ChisqTest => "_xlfn.CHISQ.TEST".to_string(), + + Function::ConfidenceNorm => "_xlfn.CONFIDENCE.NORM".to_string(), + Function::ConfidenceT => "_xlfn.CONFIDENCE.T".to_string(), + + Function::CovarianceP => "_xlfn.COVARIANCE.P".to_string(), + Function::CovarianceS => "_xlfn.COVARIANCE.S".to_string(), + + Function::ExponDist => "_xlfn.EXPON.DIST".to_string(), + + Function::FDist => "_xlfn.F.DIST".to_string(), + Function::FDistRT => "_xlfn.F.DIST.RT".to_string(), + Function::FInv => "_xlfn.F.INV".to_string(), + Function::FInvRT => "_xlfn.F.INV.RT".to_string(), + + Function::HypGeomDist => "_xlfn.HYPGEOM.DIST".to_string(), + + Function::LogNormDist => "_xlfn.LOGNORM.DIST".to_string(), + Function::LogNormInv => "_xlfn.LOGNORM.INV".to_string(), + + Function::NormDist => "_xlfn.NORM.DIST".to_string(), + Function::NormInv => "_xlfn.NORM.INV".to_string(), + Function::NormSdist => "_xlfn.NORM.S.DIST".to_string(), + Function::NormSInv => "_xlfn.NORM.S.INV".to_string(), + + Function::Phi => "_xlfn.PHI".to_string(), + + Function::PoissonDist => "_xlfn.POISSON.DIST".to_string(), + + Function::StDevP => "_xlfn.STDEV.P".to_string(), + Function::StDevS => "_xlfn.STDEV.S".to_string(), + + Function::TDist => "_xlfn.T.DIST".to_string(), + Function::TDist2T => "_xlfn.T.DIST.2T".to_string(), + Function::TDistRT => "_xlfn.T.DIST.RT".to_string(), + Function::TInv => "_xlfn.T.INV".to_string(), + Function::TInv2T => "_xlfn.T.INV.2T".to_string(), + Function::TTest => "_xlfn.T.TEST".to_string(), + + Function::VarP => "_xlfn.VAR.P".to_string(), + Function::VarS => "_xlfn.VAR.S".to_string(), + + Function::WeibullDist => "_xlfn.WEIBULL.DIST".to_string(), + Function::ZTest => "_xlfn.Z.TEST".to_string(), + _ => self.to_string(), } } @@ -1114,24 +1168,24 @@ impl Function { "BETA.DIST" | "_XLFN.BETA.DIST" => Some(Function::BetaDist), "BETA.INV" | "_XLFN.BETA.INV" => Some(Function::BetaInv), - "BINOM.DIST" => Some(Function::BinomDist), - "BINOM.DIST.RANGE" => Some(Function::BinomDistRange), - "BINOM.INV" => Some(Function::BinomInv), - "CHISQ.DIST" => Some(Function::ChisqDist), - "CHISQ.DIST.RT" => Some(Function::ChisqDistRT), - "CHISQ.INV" => Some(Function::ChisqInv), - "CHISQ.INV.RT" => Some(Function::ChisqInvRT), - "CHISQ.TEST" => Some(Function::ChisqTest), - "CONFIDENCE.NORM" => Some(Function::ConfidenceNorm), - "CONFIDENCE.T" => Some(Function::ConfidenceT), - "COVARIANCE.P" => Some(Function::CovarianceP), - "COVARIANCE.S" => Some(Function::CovarianceS), + "BINOM.DIST" | "_XLFN.BINOM.DIST" => Some(Function::BinomDist), + "BINOM.DIST.RANGE" | "_XLFN.BINOM.DIST.RANGE" => Some(Function::BinomDistRange), + "BINOM.INV" | "_XLFN.BINOM.INV" => Some(Function::BinomInv), + "CHISQ.DIST" | "_XLFN.CHISQ.DIST" => Some(Function::ChisqDist), + "CHISQ.DIST.RT" | "_XLFN.CHISQ.DIST.RT" => Some(Function::ChisqDistRT), + "CHISQ.INV" | "_XLFN.CHISQ.INV" => Some(Function::ChisqInv), + "CHISQ.INV.RT" | "_XLFN.CHISQ.INV.RT" => Some(Function::ChisqInvRT), + "CHISQ.TEST" | "_XLFN.CHISQ.TEST" => Some(Function::ChisqTest), + "CONFIDENCE.NORM" | "_XLFN.CONFIDENCE.NORM" => Some(Function::ConfidenceNorm), + "CONFIDENCE.T" | "_XLFN.CONFIDENCE.T" => Some(Function::ConfidenceT), + "COVARIANCE.P" | "_XLFN.COVARIANCE.P" => Some(Function::CovarianceP), + "COVARIANCE.S" | "_XLFN.COVARIANCE.S" => Some(Function::CovarianceS), "DEVSQ" => Some(Function::Devsq), - "EXPON.DIST" => Some(Function::ExponDist), - "F.DIST" => Some(Function::FDist), - "F.DIST.RT" => Some(Function::FDistRT), - "F.INV" => Some(Function::FInv), - "F.INV.RT" => Some(Function::FInvRT), + "EXPON.DIST" | "_XLFN.EXPON.DIST" => Some(Function::ExponDist), + "F.DIST" | "_XLFN.F.DIST" => Some(Function::FDist), + "F.DIST.RT" | "_XLFN.F.DIST.RT" => Some(Function::FDistRT), + "F.INV" | "_XLFN.F.INV" => Some(Function::FInv), + "F.INV.RT" | "_XLFN.F.INV.RT" => Some(Function::FInvRT), "FISHER" => Some(Function::Fisher), "FISHERINV" => Some(Function::FisherInv), "GAMMA" | "_XLFN.GAMMA" => Some(Function::Gamma), @@ -1139,34 +1193,34 @@ impl Function { "GAMMA.INV" | "_XLFN.GAMMA.INV" => Some(Function::GammaInv), "GAMMALN" | "_XLFN.GAMMALN" => Some(Function::GammaLn), "GAMMALN.PRECISE" | "_XLFN.GAMMALN.PRECISE" => Some(Function::GammaLnPrecise), - "HYPGEOM.DIST" => Some(Function::HypGeomDist), - "LOGNORM.DIST" => Some(Function::LogNormDist), - "LOGNORM.INV" => Some(Function::LogNormInv), - "NEGBINOM.DIST" => Some(Function::NegbinomDist), - "NORM.DIST" => Some(Function::NormDist), - "NORM.INV" => Some(Function::NormInv), - "NORM.S.DIST" => Some(Function::NormSdist), - "NORM.S.INV" => Some(Function::NormSInv), + "HYPGEOM.DIST" | "_XLFN.HYPGEOM.DIST" => Some(Function::HypGeomDist), + "LOGNORM.DIST" | "_XLFN.LOGNORM.DIST" => Some(Function::LogNormDist), + "LOGNORM.INV" | "_XLFN.LOGNORM.INV" => Some(Function::LogNormInv), + "NEGBINOM.DIST" | "_XLFN.NEGBINOM.DIST" => Some(Function::NegbinomDist), + "NORM.DIST" | "_XLFN.NORM.DIST" => Some(Function::NormDist), + "NORM.INV" | "_XLFN.NORM.INV" => Some(Function::NormInv), + "NORM.S.DIST" | "_XLFN.NORM.S.DIST" => Some(Function::NormSdist), + "NORM.S.INV" | "_XLFN.NORM.S.INV" => Some(Function::NormSInv), "PEARSON" => Some(Function::Pearson), - "PHI" => Some(Function::Phi), - "POISSON.DIST" => Some(Function::PoissonDist), + "PHI" | "_XLFN.PHI" => Some(Function::Phi), + "POISSON.DIST" | "_XLFN.POISSON.DIST" => Some(Function::PoissonDist), "STANDARDIZE" => Some(Function::Standardize), - "STDEV.P" => Some(Function::StDevP), - "STDEV.S" => Some(Function::StDevS), + "STDEV.P" | "_XLFN.STDEV.P" => Some(Function::StDevP), + "STDEV.S" | "_XLFN.STDEV.S" => Some(Function::StDevS), "STDEVA" => Some(Function::Stdeva), "STDEVPA" => Some(Function::Stdevpa), - "T.DIST" => Some(Function::TDist), - "T.DIST.2T" => Some(Function::TDist2T), - "T.DIST.RT" => Some(Function::TDistRT), - "T.INV" => Some(Function::TInv), - "T.INV.2T" => Some(Function::TInv2T), - "T.TEST" => Some(Function::TTest), - "VAR.P" => Some(Function::VarP), - "VAR.S" => Some(Function::VarS), + "T.DIST" | "_XLFN.T.DIST" => Some(Function::TDist), + "T.DIST.2T" | "_XLFN.T.DIST.2T" => Some(Function::TDist2T), + "T.DIST.RT" | "_XLFN.T.DIST.RT" => Some(Function::TDistRT), + "T.INV" | "_XLFN.T.INV" => Some(Function::TInv), + "T.INV.2T" | "_XLFN.T.INV.2T" => Some(Function::TInv2T), + "T.TEST" | "_XLFN.T.TEST" => Some(Function::TTest), + "VAR.P" | "_XLFN.VAR.P" => Some(Function::VarP), + "VAR.S" | "_XLFN.VAR.S" => Some(Function::VarS), "VARPA" => Some(Function::VarpA), "VARA" => Some(Function::VarA), - "WEIBULL.DIST" => Some(Function::WeibullDist), - "Z.TEST" => Some(Function::ZTest), + "WEIBULL.DIST" | "_XLFN.WEIBULL.DIST" => Some(Function::WeibullDist), + "Z.TEST" | "_XLFN.Z.TEST" => Some(Function::ZTest), _ => None, } diff --git a/base/src/functions/statistical/t_dist.rs b/base/src/functions/statistical/t_dist.rs index beb9b44..f545be7 100644 --- a/base/src/functions/statistical/t_dist.rs +++ b/base/src/functions/statistical/t_dist.rs @@ -391,9 +391,21 @@ impl Model { Err(e) => return e, }; - // keep only numeric entries, ignore non-numeric (Option::None) - let values1: Vec = values1_opts.into_iter().flatten().collect(); - let values2: Vec = values2_opts.into_iter().flatten().collect(); + let (values1, values2): (Vec, Vec) = if matches!(test_type, TTestType::Paired) { + values1_opts + .into_iter() + .zip(values2_opts) + .filter_map(|(o1, o2)| match (o1, o2) { + (Some(v1), Some(v2)) => Some((v1, v2)), + _ => None, // skip if either is None + }) + .unzip() + } else { + // keep only numeric entries, ignore non-numeric (Option::None) + let v1: Vec = values1_opts.into_iter().flatten().collect(); + let v2: Vec = values2_opts.into_iter().flatten().collect(); + (v1, v2) + }; let n1 = values1.len(); let n2 = values2.len(); diff --git a/xlsx/tests/statistical/AVEDEV.xlsx b/xlsx/tests/statistical/AVEDEV.xlsx new file mode 100644 index 0000000..eac1ed9 Binary files /dev/null and b/xlsx/tests/statistical/AVEDEV.xlsx differ diff --git a/xlsx/tests/statistical/BETA_DIST_INV.xlsx b/xlsx/tests/statistical/BETA_DIST_INV.xlsx new file mode 100644 index 0000000..ca0677e Binary files /dev/null and b/xlsx/tests/statistical/BETA_DIST_INV.xlsx differ diff --git a/xlsx/tests/statistical/BINOM.xlsx b/xlsx/tests/statistical/BINOM.xlsx new file mode 100644 index 0000000..05c0322 Binary files /dev/null and b/xlsx/tests/statistical/BINOM.xlsx differ diff --git a/xlsx/tests/statistical/CHISQ.xlsx b/xlsx/tests/statistical/CHISQ.xlsx new file mode 100644 index 0000000..f33f1b1 Binary files /dev/null and b/xlsx/tests/statistical/CHISQ.xlsx differ diff --git a/xlsx/tests/statistical/CHISQ_TEST.xlsx b/xlsx/tests/statistical/CHISQ_TEST.xlsx new file mode 100644 index 0000000..8a71d98 Binary files /dev/null and b/xlsx/tests/statistical/CHISQ_TEST.xlsx differ diff --git a/xlsx/tests/statistical/CONFIDENCE.xlsx b/xlsx/tests/statistical/CONFIDENCE.xlsx new file mode 100644 index 0000000..e185473 Binary files /dev/null and b/xlsx/tests/statistical/CONFIDENCE.xlsx differ diff --git a/xlsx/tests/statistical/COVARIANCE.xlsx b/xlsx/tests/statistical/COVARIANCE.xlsx new file mode 100644 index 0000000..126584b Binary files /dev/null and b/xlsx/tests/statistical/COVARIANCE.xlsx differ diff --git a/xlsx/tests/statistical/DEVSQ.xlsx b/xlsx/tests/statistical/DEVSQ.xlsx new file mode 100644 index 0000000..af31285 Binary files /dev/null and b/xlsx/tests/statistical/DEVSQ.xlsx differ diff --git a/xlsx/tests/statistical/EXPON_DIST.xlsx b/xlsx/tests/statistical/EXPON_DIST.xlsx new file mode 100644 index 0000000..68965e2 Binary files /dev/null and b/xlsx/tests/statistical/EXPON_DIST.xlsx differ diff --git a/xlsx/tests/statistical/FISHER.xlsx b/xlsx/tests/statistical/FISHER.xlsx new file mode 100644 index 0000000..7173dbc Binary files /dev/null and b/xlsx/tests/statistical/FISHER.xlsx differ diff --git a/xlsx/tests/statistical/F_DIST.xlsx b/xlsx/tests/statistical/F_DIST.xlsx new file mode 100644 index 0000000..b7d7d4d Binary files /dev/null and b/xlsx/tests/statistical/F_DIST.xlsx differ diff --git a/xlsx/tests/statistical/GAMMA.xlsx b/xlsx/tests/statistical/GAMMA.xlsx new file mode 100644 index 0000000..1516c97 Binary files /dev/null and b/xlsx/tests/statistical/GAMMA.xlsx differ diff --git a/xlsx/tests/statistical/HYPERGEOM_DIST.xlsx b/xlsx/tests/statistical/HYPERGEOM_DIST.xlsx new file mode 100644 index 0000000..2dbd6db Binary files /dev/null and b/xlsx/tests/statistical/HYPERGEOM_DIST.xlsx differ diff --git a/xlsx/tests/statistical/LOGNORM.xlsx b/xlsx/tests/statistical/LOGNORM.xlsx new file mode 100644 index 0000000..e0347a8 Binary files /dev/null and b/xlsx/tests/statistical/LOGNORM.xlsx differ diff --git a/xlsx/tests/statistical/NORM_DIST.xlsx b/xlsx/tests/statistical/NORM_DIST.xlsx new file mode 100644 index 0000000..5e73072 Binary files /dev/null and b/xlsx/tests/statistical/NORM_DIST.xlsx differ diff --git a/xlsx/tests/statistical/PEARSON.xlsx b/xlsx/tests/statistical/PEARSON.xlsx new file mode 100644 index 0000000..3d603d1 Binary files /dev/null and b/xlsx/tests/statistical/PEARSON.xlsx differ diff --git a/xlsx/tests/statistical/PHI.xlsx b/xlsx/tests/statistical/PHI.xlsx new file mode 100644 index 0000000..079c96b Binary files /dev/null and b/xlsx/tests/statistical/PHI.xlsx differ diff --git a/xlsx/tests/statistical/POISSON.xlsx b/xlsx/tests/statistical/POISSON.xlsx new file mode 100644 index 0000000..06455f0 Binary files /dev/null and b/xlsx/tests/statistical/POISSON.xlsx differ diff --git a/xlsx/tests/statistical/STANDARIZE.xlsx b/xlsx/tests/statistical/STANDARIZE.xlsx new file mode 100644 index 0000000..207647c Binary files /dev/null and b/xlsx/tests/statistical/STANDARIZE.xlsx differ diff --git a/xlsx/tests/statistical/STDEV.xlsx b/xlsx/tests/statistical/STDEV.xlsx new file mode 100644 index 0000000..13f8e8a Binary files /dev/null and b/xlsx/tests/statistical/STDEV.xlsx differ diff --git a/xlsx/tests/statistical/T_DIST.xlsx b/xlsx/tests/statistical/T_DIST.xlsx new file mode 100644 index 0000000..db139de Binary files /dev/null and b/xlsx/tests/statistical/T_DIST.xlsx differ diff --git a/xlsx/tests/statistical/T_TEST.xlsx b/xlsx/tests/statistical/T_TEST.xlsx new file mode 100644 index 0000000..5e0afb7 Binary files /dev/null and b/xlsx/tests/statistical/T_TEST.xlsx differ diff --git a/xlsx/tests/statistical/VARIANCE.xlsx b/xlsx/tests/statistical/VARIANCE.xlsx new file mode 100644 index 0000000..a046bcb Binary files /dev/null and b/xlsx/tests/statistical/VARIANCE.xlsx differ diff --git a/xlsx/tests/statistical/WEIBULL_DIST.xlsx b/xlsx/tests/statistical/WEIBULL_DIST.xlsx new file mode 100644 index 0000000..e83023c Binary files /dev/null and b/xlsx/tests/statistical/WEIBULL_DIST.xlsx differ diff --git a/xlsx/tests/statistical/Z_TEST.xlsx b/xlsx/tests/statistical/Z_TEST.xlsx new file mode 100644 index 0000000..5ba46ca Binary files /dev/null and b/xlsx/tests/statistical/Z_TEST.xlsx differ diff --git a/xlsx/tests/test.rs b/xlsx/tests/test.rs index 991bdbd..9ab44ce 100644 --- a/xlsx/tests/test.rs +++ b/xlsx/tests/test.rs @@ -373,6 +373,45 @@ fn test_xlsx() { ); } +#[test] +fn test_statistical_xlsx() { + let mut entries = fs::read_dir("tests/statistical/") + .unwrap() + .map(|res| res.map(|e| e.path())) + .collect::, io::Error>>() + .unwrap(); + entries.sort(); + let temp_folder = env::temp_dir(); + let path = format!("{}", Uuid::new_v4()); + let dir = temp_folder.join(path); + fs::create_dir(&dir).unwrap(); + let mut is_error = false; + for file_path in entries { + let file_name_str = file_path.file_name().unwrap().to_str().unwrap(); + let file_path_str = file_path.to_str().unwrap(); + println!("Testing file: {file_path_str}"); + if file_name_str.ends_with(".xlsx") && !file_name_str.starts_with('~') { + if let Err(message) = test_file(file_path_str) { + println!("Error with file: '{file_path_str}'"); + println!("{message}"); + is_error = true; + } + let t = test_load_and_saving(file_path_str, &dir); + if t.is_err() { + println!("Error while load and saving file: {file_path_str}"); + is_error = true; + } + } else { + println!("skipping"); + } + } + fs::remove_dir_all(&dir).unwrap(); + assert!( + !is_error, + "Models were evaluated inconsistently with XLSX data." + ); +} + #[test] fn no_export() { let mut entries = fs::read_dir("tests/calc_test_no_export/")