From e666397f0124f9262e53a3b129319938c1893f96 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sun, 22 Jul 2018 19:32:14 +0200 Subject: [PATCH] Correlation: cosmetics --- .paket/Paket.Restore.targets | 9 +- .../StatisticsTests/CorrelationTests.cs | 23 ++-- src/Numerics/Statistics/Correlation.cs | 116 ++++++++++-------- 3 files changed, 78 insertions(+), 70 deletions(-) diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets index 55292f31..e12083c1 100644 --- a/.paket/Paket.Restore.targets +++ b/.paket/Paket.Restore.targets @@ -71,7 +71,10 @@ false true - + + + true + @@ -132,11 +135,11 @@ - + - + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) diff --git a/src/Numerics.Tests/StatisticsTests/CorrelationTests.cs b/src/Numerics.Tests/StatisticsTests/CorrelationTests.cs index 406acc8b..18369ba1 100644 --- a/src/Numerics.Tests/StatisticsTests/CorrelationTests.cs +++ b/src/Numerics.Tests/StatisticsTests/CorrelationTests.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // -// Copyright (c) 2009-2016 Math.NET +// Copyright (c) 2009-2018 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -32,8 +32,6 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using MathNet.Numerics.Statistics; -using MathNet.Numerics.LinearAlgebra.Double; -using System.IO; using MathNet.Numerics.TestData; using System.Globalization; @@ -67,24 +65,23 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests [TestCase("numpy.CorrNumpyData_pwm.csv", 0.005)] [TestCase("numpy.CorrNumpyData_sin.csv", 0.005)] [TestCase("numpy.CorrNumpyData_rnd.csv", 0.005)] - public void TestAutocorrelation(string fName, double tol) + public void AutoCorrelationTest(string fName, double tol) { - var data = Data.ReadAllLines(fName) - .Select(line => - { - var vals = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - return new Tuple(vals[0], vals[1]); - }).ToArray(); + .Select(line => + { + var vals = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + return new Tuple(vals[0], vals[1]); + }).ToArray(); var series = data.Select(tuple => Double.Parse(tuple.Item1, CultureInfo.InvariantCulture)).ToArray(); var resNumpy = data.Select(tuple => Double.Parse(tuple.Item2, CultureInfo.InvariantCulture)).ToArray(); - - var resMathNet = Statistics.Correlation.AutoCorrelation(series); - + var resMathNet = Correlation.Auto(series); for (int i = 0; i < resMathNet.Length; i++) + { Assert.AreEqual(resNumpy[i], resMathNet[i], tol); + } } /// diff --git a/src/Numerics/Statistics/Correlation.cs b/src/Numerics/Statistics/Correlation.cs index 013a9f38..a2b870b7 100644 --- a/src/Numerics/Statistics/Correlation.cs +++ b/src/Numerics/Statistics/Correlation.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // -// Copyright (c) 2009-2014 Math.NET +// Copyright (c) 2009-2018 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -42,81 +42,88 @@ namespace MathNet.Numerics.Statistics /// public static class Correlation { - - /// - /// autocorrelation function (ACF) based on fft (usually faster then direct brute force implementation) for all possible lags k - /// First element is hidden since ACF(k = 0) = 1 - /// data array to calculate auto correlation for - /// an array with the ACF as a function of the lags k - public static double[] AutoCorrelation(IEnumerable x) + /// + /// Autocorrelation function (ACF) based on FFT for all possible lags k. + /// The first element is hidden since ACF(k = 0) = 1. + /// + /// Data array to calculate auto correlation for. + /// An array with the ACF as a function of the lags k. + public static double[] Auto(IEnumerable x) { - return autoCorrelationFft(x, 0, x.Count() - 1); + return AutoCorrelationFft(x, 0, x.Count() - 1); } - /// - /// autocorrelation function (ACF) based on fft (usually faster then direct brute force implementation) for lags - /// between kMin and kMax - /// First element is hidden since ACF(k = 0) = 1 - /// the data array to calculate auto correlation for - /// max lag to calculate ACF for must be positive and smaller than x.Length-1 - /// min lag to calculate ACF for (0 = no shift with acf=1) must be zero or positive and smaller than x.Length-1 - /// an array with the ACF as a function of the lags k - public static double[] AutoCorrelation(IEnumerable x, int kMax, int kMin = 0) + /// + /// Autocorrelation function (ACF) based on FFT for lags between kMin and kMax. + /// The first element is hidden since ACF(k = 0) = 1. + /// + /// The data array to calculate auto correlation for. + /// Max lag to calculate ACF for must be positive and smaller than x.Length-1. + /// Min lag to calculate ACF for (0 = no shift with acf=1) must be zero or positive and smaller than x.Length-1. + /// An array with the ACF as a function of the lags k. + public static double[] Auto(IEnumerable x, int kMax, int kMin = 0) { // assert max and min in proper order var kMax2 = Math.Max(kMax, kMin); var kMin2 = Math.Min(kMax, kMin); - return (autoCorrelationFft(x, kMin2, kMax2)); + return AutoCorrelationFft(x, kMin2, kMax2); } - - /// - /// autocorrelation function based on fft for lags k (faster than brute force calculation for big sample sizes). - /// First element is skipped since ACF(k = 0) = 1 - /// the data array to calculate auto correlation for - /// array with lags to calculate ACF for - /// an array with the ACF as a function of the lags k - public static double[] AutoCorrelation(IEnumerable x, int[] k) + /// + /// Autocorrelation function based on FFT for lags k. + /// The first element is hidden since ACF(k = 0) = 1. + /// + /// The data array to calculate auto correlation for. + /// Array with lags to calculate ACF for. + /// An array with the ACF as a function of the lags k. + public static double[] Auto(IEnumerable x, int[] k) { if (k == null) - throw new ArgumentNullException("k"); + { + throw new ArgumentNullException(nameof(k)); + } if (k.Length < 1) + { throw new ArgumentException("k"); + } // get acf between full range - var acf = autoCorrelationFft(x, k.Min(), k.Max()); + var acf = AutoCorrelationFft(x, k.Min(), k.Max()); // map output by indexing - var acfReturn = new double[k.Length]; - for (int i = 0; i < acfReturn.Length; i++) - acfReturn[i] = acf[k[i]]; + var result = new double[k.Length]; + for (int i = 0; i < result.Length; i++) + { + result[i] = acf[k[i]]; + } - return acfReturn; + return result; } /// - /// this is the internal core method for calculating the autocorrelation + /// The internal core method for calculating the autocorrelation. /// - /// the data array to calculate auto correlation for - /// min lag to calculate ACF for (0 = no shift with acf=1) must be zero or positive and smaller than x.Length-1 - /// max lag to calculate ACF for must be positive and smaller than x.Length-1 - /// an array with the ACF as a function of the lags k - private static double[] autoCorrelationFft(IEnumerable x, int k_low, int k_high) + /// The data array to calculate auto correlation for + /// Min lag to calculate ACF for (0 = no shift with acf=1) must be zero or positive and smaller than x.Length-1 + /// Max lag to calculate ACF for must be positive and smaller than x.Length-1 + /// An array with the ACF as a function of the lags k. + private static double[] AutoCorrelationFft(IEnumerable x, int k_low, int k_high) { if (x == null) - throw new ArgumentNullException("x"); + throw new ArgumentNullException(nameof(x)); - if (k_low < 0 || k_low >= x.Count()) - throw new ArgumentOutOfRangeException("kMin must be zero or positive and smaller than x.Length"); - if (k_high < 0 || k_high >= x.Count()) - throw new ArgumentOutOfRangeException("kMax must be positive and smaller than x.Length"); + int N = x.Count(); // Sample size + + if (k_low < 0 || k_low >= N) + throw new ArgumentOutOfRangeException(nameof(k_low), "kMin must be zero or positive and smaller than x.Length"); + if (k_high < 0 || k_high >= N) + throw new ArgumentOutOfRangeException(nameof(k_high), "kMax must be positive and smaller than x.Length"); - if (x.Count() < 1) + if (N < 1) return new double[0]; - int N = x.Count(); // Sample size int nFFT = Euclid.CeilingToPowerOfTwo(N) * 2; Complex[] x_fft = new Complex[nFFT]; @@ -133,7 +140,7 @@ namespace MathNet.Numerics.Statistics if (ii < N) { if (!iex.MoveNext()) - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentOutOfRangeException(nameof(x)); xArrNow = iex.Current; x_fft[ii] = new Complex(xArrNow - x_dash, 0.0); // copy values in range and substract mean } @@ -152,6 +159,7 @@ namespace MathNet.Numerics.Statistics } Fourier.Inverse(x_fft2, FourierOptions.Matlab); + double acf_Val1 = x_fft2[0].Real; double[] acf_Vec = new double[k_high - k_low]; @@ -163,7 +171,7 @@ namespace MathNet.Numerics.Statistics acf_Vec[ii] = x_fft2[k_low + ii + 1].Real / acf_Val1; } - return (acf_Vec); + return acf_Vec; } /// @@ -192,7 +200,7 @@ namespace MathNet.Numerics.Statistics { if (!ieB.MoveNext()) { - throw new ArgumentOutOfRangeException("dataB", Resources.ArgumentArraysSameLength); + throw new ArgumentOutOfRangeException(nameof(dataB), Resources.ArgumentArraysSameLength); } double currentA = ieA.Current; @@ -214,7 +222,7 @@ namespace MathNet.Numerics.Statistics if (ieB.MoveNext()) { - throw new ArgumentOutOfRangeException("dataA", Resources.ArgumentArraysSameLength); + throw new ArgumentOutOfRangeException(nameof(dataA), Resources.ArgumentArraysSameLength); } } @@ -248,11 +256,11 @@ namespace MathNet.Numerics.Statistics { if (!ieB.MoveNext()) { - throw new ArgumentOutOfRangeException("dataB", Resources.ArgumentArraysSameLength); + throw new ArgumentOutOfRangeException(nameof(dataB), Resources.ArgumentArraysSameLength); } if (!ieW.MoveNext()) { - throw new ArgumentOutOfRangeException("weights", Resources.ArgumentArraysSameLength); + throw new ArgumentOutOfRangeException(nameof(weights), Resources.ArgumentArraysSameLength); } ++n; @@ -277,11 +285,11 @@ namespace MathNet.Numerics.Statistics } if (ieB.MoveNext()) { - throw new ArgumentOutOfRangeException("dataB", Resources.ArgumentArraysSameLength); + throw new ArgumentOutOfRangeException(nameof(dataB), Resources.ArgumentArraysSameLength); } if (ieW.MoveNext()) { - throw new ArgumentOutOfRangeException("weights", Resources.ArgumentArraysSameLength); + throw new ArgumentOutOfRangeException(nameof(weights), Resources.ArgumentArraysSameLength); } } return covariance/Math.Sqrt(varA*varB);