diff --git a/.gitignore b/.gitignore index 7295353..be3f509 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,9 @@ DerivedData *.hmap *.ipa *.xcuserstate -.DS_Store \ No newline at end of file +.DS_Store +Distrib/SigmaDistrib.swift + +Distrib/SigmaDistrib.swift + +Distrib/SigmaDistrib.swift diff --git a/Distrib/SigmaDistrib.swift b/Distrib/SigmaDistrib.swift index 0c46919..7fd50c9 100644 --- a/Distrib/SigmaDistrib.swift +++ b/Distrib/SigmaDistrib.swift @@ -7,6 +7,59 @@ // +// ---------------------------- +// +// CoefficientVariation.swift +// +// ---------------------------- + +// +// CoefficientVariation.swift +// +// Created by Alan James Salmoni on 21/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + +import Foundation + +public extension Sigma { + /** + + Computes coefficient of variation based on a sample. + + https://en.wikipedia.org/wiki/Coefficient_of_variation + + - parameter values: Array of decimal numbers. + - returns: Coefficient of variation of a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + s = sqrt( Σ( (x - m)^2 ) / (n - 1) ) + + Where: + + m is the sample mean. + + n is the sample size. + + Example: + + Sigma.coefficient_variation([1, 12, 19.5, -5, 3, 8]) // 1.3518226671899016 + + */ + public static func coefficient_variation(_ values: [Double]) -> Double? { + if values.count > 0 { + let sampleStdDev = Sigma.standardDeviationSample(values) + let average_val = average(values) + return sampleStdDev! / average_val! + } + else { + return nil + } + } +} + + // ---------------------------- // // Covariance.swift @@ -215,6 +268,67 @@ public extension Sigma { } +// ---------------------------- +// +// Moment.swift +// +// ---------------------------- + +// +// Moment.swift +// +// Created by Alan James Salmoni on 19/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + + +import Foundation + +public extension Sigma { + /** + + Computes a specified moment based on a sample. + + https://en.wikipedia.org/wiki/Moment_(mathematics) + + - parameter values: Array of decimal numbers, dimension + - returns: Moment based on a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + [XXXX] + + Where: + + m is the required dimension. + + n is the sample size. + + Example: + + Sigma.varianceSample([1, 12, 19.5, -5, 3, 8]) // 75.24166667 + + */ + + public static func moment(_ values: [Double], m: Int ) -> Double? { + let average_val = average(values) + let count = Double(values.count) + var total: Double = 0 + var delta: Double = 0 + if values.count > 0 { + for value in values { + delta = pow((value - average_val!), Double(m)) + total += delta + } + return total / count + } + else { + return nil + } + } +} + + // ---------------------------- // // Normal.swift @@ -300,12 +414,12 @@ public extension Sigma { - parameter σ: The standard deviation. Default: 1. - - returns: the quantile function for the normal distribution. Returns nil if σ is zero or negative. Returns nil if p is negative or greater than one. Returns (-Double.infinity) if p is zero. Returns Double.infinity if p is one. + - returns: The quantile function for the normal distribution. Returns nil if σ is zero or negative. Returns nil if p is negative or greater than one. Returns (-Double.infinity) if p is zero. Returns Double.infinity if p is one. Example: - Sigma.normalQuantile(probability: 0.025, μ: 0, σ: 1) // -1.9599639845400538 + Sigma.normalQuantile(p: 0.025, μ: 0, σ: 1) // -1.9599639845400538 */ public static func normalQuantile(p: Double, μ: Double = 0, σ: Double = 1) -> Double? { @@ -369,7 +483,7 @@ public extension Sigma { - parameter σ: The standard deviation. - - returns: the quantile function for the normal distribution. Returns nil if σ is zero or negative. Returns nil if p is negative or greater than one. Returns (-Double.infinity) if p is zero. Returns Double.infinity if p is one. + - returns: The quantile function for the normal distribution. Returns nil if σ is zero or negative. Returns nil if p is negative or greater than one. Returns (-Double.infinity) if p is zero. Returns Double.infinity if p is one. */ static func qnorm(p: Double, mu: Double, sigma: Double) -> Double? { @@ -563,6 +677,169 @@ public extension Sigma { } +// ---------------------------- +// +// Quantiles.swift +// +// ---------------------------- + +// +// Quantiles.swift +// +// Created by Alan James Salmoni on 21/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + +import Foundation + +public extension Sigma { + /** + These routines calculate quantiles according to the paper by Hyndman and Fan (1996). Each routine is detailed within the routine and for types 4 through 9, Q[i](p) is a continuous function of p, with gamma = g and m given below. The sample quantiles can be obtained equivalently by linear interpolation between the points (p[k],x[k]) where x[k] is the kth order statistic. Specific expressions for p[k] are given below. + + The information was retrieved from the equivalent page about quantiles in R (http://stat.ethz.ch/R-manual/R-devel/library/stats/html/quantile.html) + + Information about quantiles in general can be found at https://en.wikipedia.org/wiki/Quantile + + */ + func QDef(data: [Double], k: Int, alpha: Double) -> Double { + /* + This routine is a common routine for all quantile methods. It takes the data as an array, a value for k and an alpha level, and calculates the appropriate quantile and returns it. + + */ + let qdef = ((1.0 - alpha)*data[k-1])+(alpha*data[k]) + return qdef + } + + func Q1(data: [Double], alpha: Double) -> Double { + /* + This calculates quantiles using the inverse of the empirical distribution function. γ = 0 if g = 0, and 1 otherwise. + */ + let data = data.sorted(by: <) + let count = data.count + let k = Int((alpha * Double(count))) + let g = (alpha * Double(count)) - Double(k) + var new_alpha = 1.0 + if g == 0.0 { + new_alpha = 0.0 + } + let Q = QDef(data: data, k: k, alpha: new_alpha) + return Q + } + + func Q2(data: [Double], alpha: Double) -> Double { + /* + Similar to type 1 but with averaging at discontinuities. γ = 0.5 if g = 0, and 1 otherwise. + */ + let data = data.sorted(by: <) + let count = data.count + let k = Int(alpha * Double(count)) + let g = (alpha * Double(count)) - Double(k) + var new_alpha = 1.0 + if g == 0.0 { + new_alpha = 0.5 + } + let Q = QDef(data: data, k: k, alpha: new_alpha) + return Q + } + + func Q3(data: [Double], alpha: Double) -> Double { + /* + SAS definition: nearest even order statistic. γ = 0 if g = 0 and j is even, and 1 otherwise. + */ + let data = data.sorted(by: <) + let count = data.count + let m = -0.5 + let k = Int((alpha * Double(count)) + m) + let g = (alpha * Double(count)) + m - Double(k) + var new_alpha = 1.0 + /* if g == 0.0 && k.truncatingRemainder(dividingBy: 2.0) != 0.0 { */ + if g == 0.0 && k % 2 != 0 { + new_alpha = 0.0 + } + let Q = QDef(data: data, k: k, alpha: new_alpha) + return Q + } + + func Q4(data: [Double], alpha: Double) -> Double { + /* + m = 0. p[k] = k / n. That is, linear interpolation of the empirical cdf. + */ + let data = data.sorted(by: <) + let count = data.count + let m = 0.0 + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = QDef(data: data, k: k, alpha: alpha) + return Q + } + + func Q5(data: [Double], alpha: Double) -> Double { + /* + m = 1/2. p[k] = (k - 0.5) / n. That is a piecewise linear function where the knots are the values midway through the steps of the empirical cdf. This is popular amongst hydrologists. + */ + let data = data.sorted(by: <) + let count = data.count + let m = 0.5 + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = QDef(data: data, k: k, alpha: alpha) + return Q + } + + func Q6(data: [Double], alpha: Double) -> Double { + /* + m = p. p[k] = k / (n + 1). Thus p[k] = E[F(x[k])]. This is used by Minitab and by SPSS. + */ + let data = data.sorted(by: <) + let count = data.count + let m = alpha + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = QDef(data: data, k: k, alpha: alpha) + return Q + } + + func Q7(data: [Double], alpha: Double) -> Double { + /* + m = 1-p. p[k] = (k - 1) / (n - 1). In this case, p[k] = mode[F(x[k])]. This is used by S. + */ + let data = data.sorted(by: <) + let count = data.count + let m = 1.0 - alpha + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = QDef(data: data, k: k, alpha: alpha) + return Q + } + + func Q8(data: [Double], alpha: Double) -> Double { + /* + m = (p+1)/3. p[k] = (k - 1/3) / (n + 1/3). Then p[k] =~ median[F(x[k])]. The resulting quantile estimates are approximately median-unbiased regardless of the distribution of x. + */ + let data = data.sorted(by: <) + let count = data.count + let m = (alpha + 1.0) / 3.0 + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = QDef(data: data, k: k, alpha: alpha) + return Q + } + + func Q9(data: [Double], alpha: Double) -> Double { + /* + m = p/4 + 3/8. p[k] = (k - 3/8) / (n + 1/4). The resulting quantile estimates are approximately unbiased for the expected order statistics if x is normally distributed. + */ + let data = data.sorted(by: <) + let count = data.count + let m = (0.25 * alpha) + (3.0 / 8.0) + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = QDef(data: data, k: k, alpha: alpha) + return Q + } +} + + // ---------------------------- // // Sigma.swift @@ -669,6 +946,103 @@ public struct Sigma { } +// ---------------------------- +// +// SkewnessKurtosis.swift +// +// ---------------------------- + +// +// SkewnessKurtosis.swift +// +// Created by Alan James Salmoni on 19/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + + +import Foundation + +public extension Sigma { + /** + + Computes skewness of a series of numbers. + + https://en.wikipedia.org/wiki/Skewness + + - parameter values: Array of decimal numbers. + - returns: Skewness based on a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + [XXXX] + + Where: + + m is the sample mean. + + n is the sample size. + + Example: + + Sigma.skewness([1, 12, 19.5, -5, 3, 8]) // 0.24527910822935245 + + */ + + public static func skewness(_ values: [Double]) -> Double? { + if values.count > 1 { + let moment3 = moment(values, m: 3) + let moment2 = moment(values, m: 2) + return moment3! / (moment2! * sqrt(moment2!)) + } + else if values.count == 1 { + return 0.0 + } + else { + return nil + } + } + + + /** + + Computes kurtosis of a series of numbers. + + https://en.wikipedia.org/wiki/Kurtosis + + - parameter values: Array of decimal numbers. + - returns: Kurtosis. Returns nil when the array is empty. + + Formula: + + [XXXX] + + Where: + + m is the population mean. + + n is the population size. + + Example: + + Sigma.kurtosis([1, 12, 19.5, -5, 3, 8]) // 2.0460654088343166 + + */ + public static func kurtosis(_ values: [Double]) -> Double? { + if values.count > 1 { + let moment4 = moment(values, m: 4) + let moment2 = moment(values, m: 2) + return (moment4! / moment2!) - 3.0 + } + else if values.count == 1 { + return 0.0 + } + else { + return nil + } + } +} + + // ---------------------------- // // StandardDeviation.swift @@ -744,6 +1118,59 @@ public extension Sigma { } +// ---------------------------- +// +// StandardError.swift +// +// ---------------------------- + +// +// StandardError.swift +// +// Created by Alan James Salmoni on 18/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + + +import Foundation + +public extension Sigma { + /** + + Computes standard error based on a sample. + + http://en.wikipedia.org/wiki/Standard_error + + - parameter values: Array of decimal numbers. + - returns: Standard error of a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + SE = sqrt( Σ( (x - m)^2 ) / (n - 1) ) / sqrt(n) + + Where: + + m is the sample mean. + + n is the sample size. + + Example: + + Sigma.standardError([1, 12, 19.5, -5, 3, 8]) // 8.674195447801869 + + */ + public static func standardError(_ values: [Double]) -> Double? { + let count = Double(values.count) + if count != 0 { + return standardDeviationSample(values)! / sqrt(count) + } + + return nil + } + +} + + // ---------------------------- // // Variance.swift diff --git a/SigmaSwiftStatistics.xcodeproj/project.pbxproj b/SigmaSwiftStatistics.xcodeproj/project.pbxproj index 0c40bca..5677f5f 100644 --- a/SigmaSwiftStatistics.xcodeproj/project.pbxproj +++ b/SigmaSwiftStatistics.xcodeproj/project.pbxproj @@ -53,6 +53,11 @@ 7EC48C961B636824002F3278 /* Sigma.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E568F8C1B19667B007862B3 /* Sigma.swift */; }; 7EE9D04D1C1CCAC500601982 /* SigmaSwiftStatistics-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EE9D04C1C1CCAC500601982 /* SigmaSwiftStatistics-tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7EE9D0521C1CCAE900601982 /* Sigma.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E568F8C1B19667B007862B3 /* Sigma.swift */; }; + E7B9FED61E10713700520306 /* CoefficientVariation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B9FED11E10713700520306 /* CoefficientVariation.swift */; }; + E7B9FED71E10713700520306 /* Moment.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B9FED21E10713700520306 /* Moment.swift */; }; + E7B9FED81E10713700520306 /* Quantiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B9FED31E10713700520306 /* Quantiles.swift */; }; + E7B9FED91E10713700520306 /* SkewnessKurtosis.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B9FED41E10713700520306 /* SkewnessKurtosis.swift */; }; + E7B9FEDA1E10713700520306 /* StandardError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B9FED51E10713700520306 /* StandardError.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -99,6 +104,11 @@ 7EE9D04A1C1CCAC500601982 /* SigmaSwiftStatistics.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SigmaSwiftStatistics.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7EE9D04C1C1CCAC500601982 /* SigmaSwiftStatistics-tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SigmaSwiftStatistics-tvOS.h"; sourceTree = ""; }; 7EE9D04E1C1CCAC500601982 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E7B9FED11E10713700520306 /* CoefficientVariation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoefficientVariation.swift; sourceTree = ""; }; + E7B9FED21E10713700520306 /* Moment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Moment.swift; sourceTree = ""; }; + E7B9FED31E10713700520306 /* Quantiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Quantiles.swift; sourceTree = ""; }; + E7B9FED41E10713700520306 /* SkewnessKurtosis.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkewnessKurtosis.swift; sourceTree = ""; }; + E7B9FED51E10713700520306 /* StandardError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardError.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -153,14 +163,19 @@ 7E568F8A1B19667B007862B3 /* SigmaSwiftStatistics */ = { isa = PBXGroup; children = ( + E7B9FED11E10713700520306 /* CoefficientVariation.swift */, 7E568F8B1B19667B007862B3 /* Info.plist */, 7E8B278D1DC36CC30002C52F /* Covariance.swift */, 7E8B278B1DC36BD40002C52F /* Median.swift */, + E7B9FED21E10713700520306 /* Moment.swift */, 7E11CD251DC3496300FDEDB7 /* Normal.swift */, 7E8B27A41DC36E920002C52F /* Pearson.swift */, 7E8B279F1DC36E420002C52F /* Percentile.swift */, + E7B9FED31E10713700520306 /* Quantiles.swift */, 7E568F8C1B19667B007862B3 /* Sigma.swift */, + E7B9FED41E10713700520306 /* SkewnessKurtosis.swift */, 7E8B278F1DC36D150002C52F /* StandardDeviation.swift */, + E7B9FED51E10713700520306 /* StandardError.swift */, 7E8B27911DC36DD60002C52F /* Variance.swift */, 7E568F8D1B19667B007862B3 /* SwiftStatistics.h */, ); @@ -518,6 +533,11 @@ 7E8B27A51DC36E920002C52F /* Pearson.swift in Sources */, 7E8B27921DC36DD60002C52F /* Variance.swift in Sources */, 7E8B27901DC36D150002C52F /* StandardDeviation.swift in Sources */, + E7B9FEDA1E10713700520306 /* StandardError.swift in Sources */, + E7B9FED71E10713700520306 /* Moment.swift in Sources */, + E7B9FED91E10713700520306 /* SkewnessKurtosis.swift in Sources */, + E7B9FED61E10713700520306 /* CoefficientVariation.swift in Sources */, + E7B9FED81E10713700520306 /* Quantiles.swift in Sources */, 7E8B278E1DC36CC30002C52F /* Covariance.swift in Sources */, 7E8B278C1DC36BD40002C52F /* Median.swift in Sources */, 7E8B27A01DC36E420002C52F /* Percentile.swift in Sources */, diff --git a/SigmaSwiftStatistics/CoefficientVariation.swift b/SigmaSwiftStatistics/CoefficientVariation.swift new file mode 100644 index 0000000..45c7af1 --- /dev/null +++ b/SigmaSwiftStatistics/CoefficientVariation.swift @@ -0,0 +1,45 @@ +// +// CoefficientVariation.swift +// +// Created by Alan James Salmoni on 21/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + +import Foundation + +public extension Sigma { + /** + + Computes coefficient of variation based on a sample. + + https://en.wikipedia.org/wiki/Coefficient_of_variation + + - parameter values: Array of decimal numbers. + - returns: Coefficient of variation of a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + s = sqrt( Σ( (x - m)^2 ) / (n - 1) ) + + Where: + + m is the sample mean. + + n is the sample size. + + Example: + + Sigma.coefficient_variation([1, 12, 19.5, -5, 3, 8]) // 1.3518226671899016 + + */ + public static func coefficient_variation(_ values: [Double]) -> Double? { + if values.count > 0 { + let sampleStdDev = Sigma.standardDeviationSample(values) + let average_val = average(values) + return sampleStdDev! / average_val! + } + else { + return nil + } + } +} diff --git a/SigmaSwiftStatistics/EffectSizes.swift b/SigmaSwiftStatistics/EffectSizes.swift new file mode 100644 index 0000000..be397df --- /dev/null +++ b/SigmaSwiftStatistics/EffectSizes.swift @@ -0,0 +1,54 @@ +// +// EffectSizes.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 30/12/2016. +// Copyright © 2016 Alan James Salmoni. All rights reserved. +// + +import Foundation + + +public extension Sigma { + + internal static func calcEffectSizeControl(data1: [Double], data2: [Double]) -> Double { + let all_data = data1 + data2 + let samp_std_dev = standardDeviationSample(all_data) + let mean1 = average(data1) + let mean2 = average(data2) + var return_val = (mean1! - mean2!) / samp_std_dev! + if return_val < 0 { + return_val = -return_val + } + return return_val + } + + public static func effectSizeControl(data1: [Double], data2: [Double]) -> Double? { + let count1 = data1.count + let count2 = data2.count + if count1 == 0 || count2 == 0 { + return nil + } + let effect_size = calcEffectSizeControl(data1: data1, data2: data2) + return effect_size + } + + internal static func calcEffectSize(data1: [Double], data2: [Double]) -> Double { + let sstd1 = standardDeviationSample(data1) + let sstd2 = standardDeviationSample(data2) + let Psd = sqrt((pow(sstd1!, 2) + pow(sstd2!, 2)) / 2.0) + let ES = (average(data1)! - average(data2)! / Psd) + return ES + } + + public static func effectSize(data1: [Double], data2: [Double]) -> Double? { + let count1 = data1.count + let count2 = data2.count + if count1 == 0 || count2 == 0 { + return nil + } + let return_val = calcEffectSize(data1: data1, data2: data2) + return return_val + } + +} diff --git a/SigmaSwiftStatistics/Frequencies.swift b/SigmaSwiftStatistics/Frequencies.swift new file mode 100644 index 0000000..0031eff --- /dev/null +++ b/SigmaSwiftStatistics/Frequencies.swift @@ -0,0 +1,45 @@ +// +// Frequencies.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 21/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import Foundation + +public extension Sigma { + + public static func frequencies(values: [Double]) -> ([Double], [Int])? { + /* + This returns two lists from an array, the first containing the unique values and the second containing how often each value occurs. + + Parameter values: + - Array of doubles to be analysed + + Return values: + - Two arrays as a tuple: + - An array containing all the values that occur within the parameter's array (see uniqueValues) + - An array containing how often each value occurs in the parameter's array + + Example: + Sigma.frequencies([1,2,3,4,5,4,3,5]) // ([1,2,3,4,5], [1, 1, 2, 2, 2]) + + Would this be better returned as a dictionary with each unique value a key and the frequency the value? + + */ + let count = values.count + if count == 0 { return nil } + let unique_vals = Sigma.uniqueValues(values: values)!.sorted(by: <) + let count_uniques = unique_vals.count + var frequencies = [Int](repeating: 0, count: count_uniques) + for (idx_uniques, unique_val) in unique_vals.enumerated() { + for datum in values { + if unique_val == datum { + frequencies[idx_uniques] += 1 + } + } + } + return (unique_vals, frequencies) + } +} diff --git a/SigmaSwiftStatistics/GeometricMean.swift b/SigmaSwiftStatistics/GeometricMean.swift new file mode 100644 index 0000000..26ffbd8 --- /dev/null +++ b/SigmaSwiftStatistics/GeometricMean.swift @@ -0,0 +1,26 @@ +// +// GeometricMean.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 30/12/2016. +// Copyright © 2016 Evgenii Neumerzhitckii. All rights reserved. +// +import Foundation + +public extension Sigma { + + public static func geometricMean(data: [Double]) -> Double? { + let count = data.count + if count == 0 { + return nil + } + var data_log: [Double] = [] + var log_val: Double + for item in data { + log_val = log(item) + data_log.append(log_val) + } + let return_val = exp(average(data_log)!) + return return_val + } +} diff --git a/SigmaSwiftStatistics/HarmonicMean.swift b/SigmaSwiftStatistics/HarmonicMean.swift new file mode 100644 index 0000000..147b8ce --- /dev/null +++ b/SigmaSwiftStatistics/HarmonicMean.swift @@ -0,0 +1,28 @@ + +// +// HarmonicMean.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 30/12/2016. +// Copyright © 2016 Evgenii Neumerzhitckii. All rights reserved. +// +import Foundation + +public extension Sigma { + + public static func harmonicMean(data: [Double]) -> Double? { + let count = data.count + if count == 0 { + return nil + } + var data_inv: [Double] = [] + var inv_val: Double + for item in data { + inv_val = 1.0 / item + data_inv.append(inv_val) + } + let m1 = average(data_inv) + let hm = 1.0 / m1! + return hm + } +} diff --git a/SigmaSwiftStatistics/Mode.swift b/SigmaSwiftStatistics/Mode.swift new file mode 100644 index 0000000..28fcadc --- /dev/null +++ b/SigmaSwiftStatistics/Mode.swift @@ -0,0 +1,48 @@ +// +// Mode.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 19/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import Foundation + +public extension Sigma { + /** + + Returns the mode(s) from the array after it is sorted and the indices where it occurs + + https://en.wikipedia.org/wiki/Mode_(statistics) + + - parameter values: Array of decimal numbers. + - returns: The mode value itself and an array of the indices where the mode occurs + + Example: + + Sigma.mode([1, 12, 9.5, 3, -5, 12]) // (12, [1,5]) + + */ + public static func mode(_ values: [Double]) -> (Double, [Int])? { + let count = values.count + if count == 0 { return nil } + else if count == 1 { + return (values[0], [0]) + } + var mode_value = values[0] + var mode_indices: [Int] = [0] + + for index in 1...(count - 1) { + if values[index] > mode_value { + mode_value = values[index] + mode_indices = [index] + } + else if values[index] == mode_value { + mode_indices.append(index) + } + } + return (mode_value, mode_indices) + } +} + + diff --git a/SigmaSwiftStatistics/Moment.swift b/SigmaSwiftStatistics/Moment.swift new file mode 100644 index 0000000..cc2627f --- /dev/null +++ b/SigmaSwiftStatistics/Moment.swift @@ -0,0 +1,53 @@ +// +// Moment.swift +// +// Created by Alan James Salmoni on 19/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + + +import Foundation + +public extension Sigma { + /** + + Computes a specified moment based on a sample. + + https://en.wikipedia.org/wiki/Moment_(mathematics) + + - parameter values: Array of decimal numbers, dimension + - returns: Moment based on a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + [XXXX] + + Where: + + m is the required dimension. + + n is the sample size. + + Example: + + Sigma.varianceSample([1, 12, 19.5, -5, 3, 8]) // 75.24166667 + + */ + + public static func moment(_ values: [Double], m: Int ) -> Double? { + let average_val = average(values) + let count = Double(values.count) + var total: Double = 0 + var delta: Double = 0 + if values.count > 0 { + for value in values { + delta = pow((value - average_val!), Double(m)) + total += delta + } + return total / count + } + else { + return nil + } + } +} diff --git a/SigmaSwiftStatistics/Quantiles.swift b/SigmaSwiftStatistics/Quantiles.swift new file mode 100644 index 0000000..ad3384c --- /dev/null +++ b/SigmaSwiftStatistics/Quantiles.swift @@ -0,0 +1,180 @@ +// +// Quantiles.swift +// +// Created by Alan James Salmoni on 21/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + +import Foundation + +public extension Sigma { + /** + These routines calculate quantiles according to the paper by Hyndman and Fan (1996). Each routine is detailed within the routine and for types 4 through 9, Q[i](p) is a continuous function of p, with gamma = g and m given below. The sample quantiles can be obtained equivalently by linear interpolation between the points (p[k],x[k]) where x[k] is the kth order statistic. Specific expressions for p[k] are given below. + + The information was retrieved from the equivalent page about quantiles in R (http://stat.ethz.ch/R-manual/R-devel/library/stats/html/quantile.html) + + Information about quantiles in general can be found at https://en.wikipedia.org/wiki/Quantile + */ + private static func qDef(data: [Double], k: Int, alpha: Double) -> Double { + /* + This routine is a common routine for all quantile methods. It takes the data as an array, a value for k and an alpha level, and calculates the appropriate quantile and returns it. + + */ + let qdef = ((1.0 - alpha)*data[k-1])+(alpha*data[k]) + return qdef + } + + public static func quantile1(data: [Double], alpha: Double) -> Double { + /* + This calculates quantiles using the inverse of the empirical distribution function. γ = 0 if g = 0, and 1 otherwise. + */ + let data = data.sorted(by: <) + let count = data.count + let k = Int((alpha * Double(count))) + let g = (alpha * Double(count)) - Double(k) + var new_alpha = 1.0 + if g == 0.0 { + new_alpha = 0.0 + } + let Q = qDef(data: data, k: k, alpha: new_alpha) + return Q + } + + public static func quantile2(data: [Double], alpha: Double) -> Double { + /* + Similar to type 1 but with averaging at discontinuities. γ = 0.5 if g = 0, and 1 otherwise. + */ + let data = data.sorted(by: <) + let count = data.count + let k = Int(alpha * Double(count)) + let g = (alpha * Double(count)) - Double(k) + var new_alpha = 1.0 + if g == 0.0 { + new_alpha = 0.5 + } + let Q = qDef(data: data, k: k, alpha: new_alpha) + return Q + } + + public static func quantile3(data: [Double], alpha: Double) -> Double { + /* + SAS definition: nearest even order statistic. γ = 0 if g = 0 and j is even, and 1 otherwise. + */ + let data = data.sorted(by: <) + let count = data.count + let m = -0.5 + let k = Int((alpha * Double(count)) + m) + let g = (alpha * Double(count)) + m - Double(k) + var new_alpha = 1.0 + /* if g == 0.0 && k.truncatingRemainder(dividingBy: 2.0) != 0.0 { */ + if g == 0.0 && k % 2 != 0 { + new_alpha = 0.0 + } + let Q = qDef(data: data, k: k, alpha: new_alpha) + return Q + } + + public static func quantile4(data: [Double], alpha: Double) -> Double { + /* + m = 0. p[k] = k / n. That is, linear interpolation of the empirical cdf. + */ + let data = data.sorted(by: <) + let count = data.count + let m = 0.0 + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = qDef(data: data, k: k, alpha: alpha) + return Q + } + + public static func quantile5(data: [Double], alpha: Double) -> Double { + /* + m = 1/2. p[k] = (k - 0.5) / n. That is a piecewise linear function where the knots are the values midway through the steps of the empirical cdf. This is popular amongst hydrologists. + */ + let data = data.sorted(by: <) + let count = data.count + let m = 0.5 + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = qDef(data: data, k: k, alpha: alpha) + return Q + } + + public static func quantile6(data: [Double], alpha: Double) -> Double { + /* + m = p. p[k] = k / (n + 1). Thus p[k] = E[F(x[k])]. This is used by Minitab and by SPSS. + */ + let data = data.sorted(by: <) + let count = data.count + let m = alpha + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = qDef(data: data, k: k, alpha: alpha) + return Q + } + + public static func quantile7(data: [Double], alpha: Double) -> Double { + /* + m = 1-p. p[k] = (k - 1) / (n - 1). In this case, p[k] = mode[F(x[k])]. This is used by S. + */ + let data = data.sorted(by: <) + let count = data.count + let m = 1.0 - alpha + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = qDef(data: data, k: k, alpha: alpha) + return Q + } + + public static func quantile8(data: [Double], alpha: Double) -> Double { + /* + m = (p+1)/3. p[k] = (k - 1/3) / (n + 1/3). Then p[k] =~ median[F(x[k])]. The resulting quantile estimates are approximately median-unbiased regardless of the distribution of x. + */ + let data = data.sorted(by: <) + let count = data.count + let m = (alpha + 1.0) / 3.0 + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = qDef(data: data, k: k, alpha: alpha) + return Q + } + + public static func quantile9(data: [Double], alpha: Double) -> Double { + /* + m = p/4 + 3/8. p[k] = (k - 3/8) / (n + 1/4). The resulting quantile estimates are approximately unbiased for the expected order statistics if x is normally distributed. + */ + let data = data.sorted(by: <) + let count = data.count + let m = (0.25 * alpha) + (3.0 / 8.0) + let k = Int((alpha * Double(count)) + m) + let alpha = (alpha * Double(count)) + m - Double(k) + let Q = qDef(data: data, k: k, alpha: alpha) + return Q + } + + public static func quantile(data: [Double], alpha: Double, qtype: Int = 7) -> Double? { + /* + A function to call quantiles. Users can specify which type of quantile they wish to use. + Quantile number 7 is the default as per R. + */ + let count = data.count + if count < 4 { + return nil + } + if alpha < 0.0 || alpha > 1.0 { + return nil + } + switch qtype { + case 1: return quantile1(data: data, alpha: alpha) + case 2: return quantile2(data: data, alpha: alpha) + case 3: return quantile3(data: data, alpha: alpha) + case 4: return quantile4(data: data, alpha: alpha) + case 5: return quantile5(data: data, alpha: alpha) + case 6: return quantile6(data: data, alpha: alpha) + case 7: return quantile7(data: data, alpha: alpha) + case 8: return quantile8(data: data, alpha: alpha) + case 9: return quantile9(data: data, alpha: alpha) + default: return nil + } + } +} diff --git a/SigmaSwiftStatistics/Ranks.swift b/SigmaSwiftStatistics/Ranks.swift new file mode 100644 index 0000000..a769dcc --- /dev/null +++ b/SigmaSwiftStatistics/Ranks.swift @@ -0,0 +1,88 @@ +// +// Ranks.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 21/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import Foundation + +public extension Sigma { + + /* + this ranks a vector (single dimensional array) of floats. + + Parameter values: + - Array of doubles to be ranked + - Start value for ranking (defaults to 1) + - How to deal with ties. Defaults to "mean" + - "mean" uses the arithmetic mean, + - "max" uses the maximum possible rank for all ties + - "min" uses the minimum rank for all ties + - "first" awards a descending rank starting so first occurence gets the highest rank down to the last + - "last" awards an ascending rank starting so the last occurance gets the highest rank down to the first + + Returns: + - Array of floats with the rank of each item + + Examples: + Sigma.rank([2,3,6,5,3]) // [1.0, 2.5, 5.0, 4.0, 2.5] + Sigma.rank([100,100,100,100], start: 10) // [11.5, 11.5, 11.5, 11.5] + Sigma.rank([100,100,100,100], ties: "max") // [1.0, 1.0, 1.0, 1.0] + Sigma.rank([100,100,100,100], ties: "min") // [4.0, 4.0, 4.0, 4.0] + Sigma.rank([100,100,100,100], ties: "first") // [1.0, 2.0, 3.0, 4.0] + Sigma.rank([100,100,100,100], ties: "last") // [4.0, 3.0, 2.0, 1.0] + + */ + + public static func rank(_ values: [Double], start: Double = 1.0, ties: String = "mean") -> [Double]? { + let count_all = values.count + if count_all == 0 { + return nil + } + var rank: Double + if ties == "mean" { + rank = start - 0.5 + } + else if ties == "max" || ties == "min" || ties == "first" || ties == "last" { + rank = start - 1.0 + } + else { + return nil + } + var increment: Double + var tiny_increment: Double + var unique_vals: [Double] + var unique_freqs: [Int] + (unique_vals, unique_freqs) = Sigma.frequencies(values: values)! + var ranks = [Double](repeating: 0, count: count_all) + for (idx, value) in unique_vals.enumerated() { + increment = Double(unique_freqs[idx]) + tiny_increment = 1.0 + for idx in 0...(count_all - 1) { + if value == values[idx] { + if ties == "mean" { + ranks[idx] = rank + (increment / 2.0) + } + else if ties == "min" { + ranks[idx] = rank + 1 + } + else if ties == "max" { + ranks[idx] = rank + increment + } + else if ties == "first" { + ranks[idx] = rank + tiny_increment + tiny_increment += 1 + } + else if ties == "last" { + ranks[idx] = rank + increment - tiny_increment + 1.0 + tiny_increment += 1 + } + } + } + rank += increment + } + return ranks + } +} diff --git a/SigmaSwiftStatistics/SkewnessKurtosis.swift b/SigmaSwiftStatistics/SkewnessKurtosis.swift new file mode 100644 index 0000000..2707aa4 --- /dev/null +++ b/SigmaSwiftStatistics/SkewnessKurtosis.swift @@ -0,0 +1,89 @@ +// +// SkewnessKurtosis.swift +// +// Created by Alan James Salmoni on 19/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + + +import Foundation + +public extension Sigma { + /** + + Computes skewness of a series of numbers. + + https://en.wikipedia.org/wiki/Skewness + + - parameter values: Array of decimal numbers. + - returns: Skewness based on a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + [XXXX] + + Where: + + m is the sample mean. + + n is the sample size. + + Example: + + Sigma.skewness([1, 12, 19.5, -5, 3, 8]) // 0.24527910822935245 + + */ + + public static func skewness(_ values: [Double]) -> Double? { + if values.count > 1 { + let moment3 = moment(values, m: 3) + let moment2 = moment(values, m: 2) + return moment3! / (moment2! * sqrt(moment2!)) + } + else if values.count == 1 { + return 0.0 + } + else { + return nil + } + } + + + /** + + Computes kurtosis of a series of numbers. + + https://en.wikipedia.org/wiki/Kurtosis + + - parameter values: Array of decimal numbers. + - returns: Kurtosis. Returns nil when the array is empty. + + Formula: + + [XXXX] + + Where: + + m is the population mean. + + n is the population size. + + Example: + + Sigma.kurtosis([1, 12, 19.5, -5, 3, 8]) // 2.0460654088343166 + + */ + public static func kurtosis(_ values: [Double]) -> Double? { + if values.count > 1 { + let moment4 = moment(values, m: 4) + let moment2 = moment(values, m: 2) + return (moment4! / moment2!) - 3.0 + } + else if values.count == 1 { + return 0.0 + } + else { + return nil + } + } +} diff --git a/SigmaSwiftStatistics/StandardError.swift b/SigmaSwiftStatistics/StandardError.swift new file mode 100644 index 0000000..b29a2a2 --- /dev/null +++ b/SigmaSwiftStatistics/StandardError.swift @@ -0,0 +1,45 @@ +// +// StandardError.swift +// +// Created by Alan James Salmoni on 18/12/2016. +// Copyright © 2016 Thought Into Design Ltd. All rights reserved. +// + + +import Foundation + +public extension Sigma { + /** + + Computes standard error based on a sample. + + http://en.wikipedia.org/wiki/Standard_error + + - parameter values: Array of decimal numbers. + - returns: Standard error of a sample. Returns nil when the array is empty or contains a single value. + + Formula: + + SE = sqrt( Σ( (x - m)^2 ) / (n - 1) ) / sqrt(n) + + Where: + + m is the sample mean. + + n is the sample size. + + Example: + + Sigma.standardError([1, 12, 19.5, -5, 3, 8]) // 8.674195447801869 + + */ + public static func standardError(_ values: [Double]) -> Double? { + let count = Double(values.count) + if count != 0 { + return standardDeviationSample(values)! / sqrt(count) + } + + return nil + } + +} diff --git a/SigmaSwiftStatistics/UniqueValues.swift b/SigmaSwiftStatistics/UniqueValues.swift new file mode 100644 index 0000000..f47c047 --- /dev/null +++ b/SigmaSwiftStatistics/UniqueValues.swift @@ -0,0 +1,33 @@ +// +// UniqueValues.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 21/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import Foundation + +public extension Sigma { + + /* + This returns a list of the values within a vector without regard to frequency + + Parameter values: + - Array of doubles to be analysed + + Return values: + - An unsorted array containing all values that occur within the parameter array. All duplicates are returned as a single value + + Example: + Sigma.uniqueValues([1,2,3,4,5,4,3,5]) // [1,2,3,4,5] + + */ + + public static func uniqueValues(values: [Double]) -> [Double]? { + let count = Double(values.count) + if count == 0 { return nil } + let unique = Array(Set(values)) + return unique + } +} diff --git a/SigmaSwiftStatisticsTests/FrequenciesTests.swift b/SigmaSwiftStatisticsTests/FrequenciesTests.swift new file mode 100644 index 0000000..8fad3e6 --- /dev/null +++ b/SigmaSwiftStatisticsTests/FrequenciesTests.swift @@ -0,0 +1,72 @@ +import XCTest +import SigmaSwiftStatistics + +class FrequenciesTests: XCTestCase { +// MARK: - Frequencies + + func testEmptyArray() { + if let _ = Sigma.frequencies(values: []) { + XCTFail() + } + else { + XCTAssertNil(nil) + } + } + + func testSingleArray() { + if let result = Sigma.frequencies(values: [-99.999]) { + let (unique_values, value_frequencies) = result + // (-99.999, [1]) + XCTAssertEqual([-99.999], unique_values) + XCTAssertEqual([1], value_frequencies) + } + else { + XCTAssertNil(nil) + } + } + + func testHomogenousArray() { + if let result = Sigma.frequencies(values: [-99.999, -99.999, -99.999, -99.999, -99.999, -99.999]) { + let (unique_values, value_frequencies) = result + // (-99.999, [6]) + XCTAssertEqual([-99.999], unique_values) + XCTAssertEqual([6], value_frequencies) + } + else { + XCTAssertNil(nil) + } + } + + func testPositiveArray() { + if let result = Sigma.frequencies(values: [6,2,9999,9999,2,79,6,6]) { + let (unique_values, value_frequencies) = result + // (2,6,79,9999, [2,3,1,2]) + XCTAssertEqual([2,6,79,9999], unique_values) + XCTAssertEqual([2,3,1,2], value_frequencies) + } + else { + XCTAssertNil(nil) + } + } + + func testNegativeArray() { + if let result = Sigma.frequencies(values: [-99.999, -0.0001, -99.999, -99.999, -99.999, -99.999]) { + let (unique_values, value_frequencies) = result + // (-99.999, [1]) + XCTAssertEqual([-99.999, -0.0001], unique_values) + XCTAssertEqual([5,1], value_frequencies) + } + else { + XCTAssertNil(nil) + } + } + + func testMixedArray() { + if let result = Sigma.frequencies(values: [-99.999, -99.999, -99.999, 99.999, -99.999, 99.999]) { + let (unique_values, value_frequencies) = result + // (-99.999, [1]) + XCTAssertEqual([-99.999, 99.999], unique_values) + XCTAssertEqual([4,2], value_frequencies) + } + } +} diff --git a/SigmaSwiftStatisticsTests/GeometricMeanTests.swift b/SigmaSwiftStatisticsTests/GeometricMeanTests.swift new file mode 100644 index 0000000..5aa8de5 --- /dev/null +++ b/SigmaSwiftStatisticsTests/GeometricMeanTests.swift @@ -0,0 +1,45 @@ +import XCTest +import SigmaSwiftStatistics + +class GeometricMeanTests: XCTestCase { + + func testGeometricMean_Normal() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + if let result = Sigma.geometricMean(data: data_array) { + XCTAssertEqualWithAccuracy(0.34079044910152717, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testGeometricMean_EmptyArray() { + let data_array: [Double] = [] + if let _ = Sigma.geometricMean(data: data_array) { + XCTFail() + } + else { + XCTAssertNil(nil) + } + } + + func testGeometricMean_SingleElement() { + let data_array = [0.52662978] + if let result = Sigma.geometricMean(data: data_array) { + XCTAssertEqualWithAccuracy(0.52662978000000005, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + +} diff --git a/SigmaSwiftStatisticsTests/HarmonicMeanTests.swift b/SigmaSwiftStatisticsTests/HarmonicMeanTests.swift new file mode 100644 index 0000000..d95df50 --- /dev/null +++ b/SigmaSwiftStatisticsTests/HarmonicMeanTests.swift @@ -0,0 +1,45 @@ +import XCTest +import SigmaSwiftStatistics + +class HarmonicMeanTests: XCTestCase { + + func testHarmonicMean_Normal() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + if let result = Sigma.harmonicMean(data: data_array) { + XCTAssertEqualWithAccuracy(0.17589575818127001, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testGeometricMean_EmptyArray() { + let data_array: [Double] = [] + if let _ = Sigma.harmonicMean(data: data_array) { + XCTFail() + } + else { + XCTAssertNil(nil) + } + } + + func testGeometricMean_SingleElement() { + let data_array = [0.52662978] + if let result = Sigma.harmonicMean(data: data_array) { + XCTAssertEqualWithAccuracy(0.52662978000000005, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + +} diff --git a/SigmaSwiftStatisticsTests/ModeTests.swift b/SigmaSwiftStatisticsTests/ModeTests.swift new file mode 100644 index 0000000..b56672a --- /dev/null +++ b/SigmaSwiftStatisticsTests/ModeTests.swift @@ -0,0 +1,119 @@ +// +// ModeTests.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 19/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import XCTest +import SigmaSwiftStatistics + +class ModeTests: XCTestCase { + + func testMode_normalList() { + if let result = Sigma.mode([1, 12, 9.5, 3, -5, 12]) { + let (mode_value, mode_indices) = result + // (12, [1,5]) + XCTAssertEqual(12, mode_value) + XCTAssertEqual([1,5], mode_indices) + } + else { + XCTFail() + } + } + + func testMode_negativeList() { + if let result = Sigma.mode([-0.000001, -4, -5, -10, -1.43242, -0.0001]) { + let (mode_value, mode_indices) = result + // (-0.000001, [0]) + XCTAssertEqual(-0.000001, mode_value) + XCTAssertEqual([0], mode_indices) + } + else { + XCTFail() + } + } + + func testMode_singleItemList() { + if let result = Sigma.mode([1]) { + let (mode_value, mode_indices) = result + // (1, [0]) + XCTAssertEqual(1, mode_value) + XCTAssertEqual([0], mode_indices) + } + else { + XCTFail() + } + } + + func testMode_singleZeroItem() { + if let result = Sigma.mode([0]) { + let (mode_value, mode_indices) = result + // (0, [0]) + XCTAssertEqual(0, mode_value) + XCTAssertEqual([0], mode_indices) + } + else { + XCTFail() + } + } + + func testMode_emptyList() { + let test_data: [Double] = [] + if let _ = Sigma.mode(test_data) { + XCTFail() + } + else { + XCTAssertNil(nil) + } + } + + func testMode_positiveNegativeList() { + if let result = Sigma.mode([-1, 12, -9.5, 3, -5, -12]) { + let (mode_value, mode_indices) = result + // (12, [1]) + XCTAssertEqual(12, mode_value) + XCTAssertEqual([1], mode_indices) + } + else { + XCTAssertNil(nil) + } + } + + func testMode_allModes() { + if let result = Sigma.mode([12, 12, 12, 12, 12, 12, 12, 12, 12]) { + let (mode_value, mode_indices) = result + // (12, [0,1,2,3,4,5,6,7,8]) + XCTAssertEqual(12, mode_value) + XCTAssertEqual([0,1,2,3,4,5,6,7,8], mode_indices) + } + else { + XCTAssertNil(nil) + } + } + + func testMode_allZeroModes() { + if let result = Sigma.mode([0, 0, 0, 0, 0, 0, 0, 0]) { + let (mode_value, mode_indices) = result + // (0, [0,0,0,0,0,0,0,0]) + XCTAssertEqual(0, mode_value) + XCTAssertEqual([0,1,2,3,4,5,6,7], mode_indices) + } + else { + XCTAssertNil(nil) + } + } + + func testMode_slightDifference() { + if let result = Sigma.mode([4, 7.7777777, 5, 6, -33, 7.777777, 0, 7.7777777]) { + let (mode_value, mode_indices) = result + // (7.7777777, [1,7]) + XCTAssertEqual(7.7777777, mode_value) + XCTAssertEqual([1,7], mode_indices) + } + else { + XCTAssertNil(nil) + } + } +} diff --git a/SigmaSwiftStatisticsTests/MomentTests.swift b/SigmaSwiftStatisticsTests/MomentTests.swift new file mode 100644 index 0000000..db6b6b9 --- /dev/null +++ b/SigmaSwiftStatisticsTests/MomentTests.swift @@ -0,0 +1,128 @@ +import XCTest +import SigmaSwiftStatistics + +class MomentTests: XCTestCase { + + func testMoment0() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let moment = 0 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(1.0, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testMoment1() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let moment = 1 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(0.0, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testMoment2() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let moment = 2 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(0.077722199012376397, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testMoment3() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let moment = 3 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(0.0013903598882142676, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testMoment4() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let moment = 4 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(0.011763602339155939, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testMomentEmpty() { + let data_array: [Double] = [] + let moment = 2 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(0.011763602339155939, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testMomentSingle() { + let data_array: [Double] = [-99.999] + let moment = 2 + if let result = Sigma.moment(data_array, m: moment) { + XCTAssertEqualWithAccuracy(0.0, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + +} diff --git a/SigmaSwiftStatisticsTests/QuantilesTests.swift b/SigmaSwiftStatisticsTests/QuantilesTests.swift new file mode 100644 index 0000000..7b8b844 --- /dev/null +++ b/SigmaSwiftStatisticsTests/QuantilesTests.swift @@ -0,0 +1,193 @@ +// +// QuantilesTests.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 19/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import XCTest +import SigmaSwiftStatistics + +class QuantilesTests: XCTestCase { + + func testQuantile1() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 1) { + XCTAssertEqualWithAccuracy(0.7165671, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile2() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 2) { + XCTAssertEqualWithAccuracy(0.7175512, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile3() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 3) { + XCTAssertEqualWithAccuracy(0.7165671, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile4() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 4) { + XCTAssertEqualWithAccuracy(0.7165671, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile5() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 5) { + XCTAssertEqualWithAccuracy(0.7175512, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile6() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 6) { + XCTAssertEqualWithAccuracy(0.7181416, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile7() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 7) { + XCTAssertEqualWithAccuracy(0.7169607, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile8() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 8) { + XCTAssertEqualWithAccuracy(0.717748, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } + + func testQuantile9() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + let alpha_value = 0.80 + if let result = Sigma.quantile(data: data_array, alpha: alpha_value, qtype: 9) { + XCTAssertEqualWithAccuracy(0.7176988, result, accuracy: 0.0000001) + } + else { + XCTAssertNil(nil) + } + } +} diff --git a/SigmaSwiftStatisticsTests/RanksTest.swift b/SigmaSwiftStatisticsTests/RanksTest.swift new file mode 100644 index 0000000..3da8061 --- /dev/null +++ b/SigmaSwiftStatisticsTests/RanksTest.swift @@ -0,0 +1,97 @@ +// +// RanksTest.swift +// SigmaSwiftStatistics +// +// Created by Alan James Salmoni on 21/01/2017. +// Copyright © 2017 Evgenii Neumerzhitckii. All rights reserved. +// + +import XCTest +import SigmaSwiftStatistics + +class RanksTests: XCTestCase { + + // MARK: - ranking data + + func testRanksEmpty() { + let result = Sigma.rank([]) + XCTAssertNil(result) + } + + func testRanksSingle() { + let data = [50.0] + let result = Sigma.rank(data)! + XCTAssertEqual([1.0], result) + } + + func testRanksTiesMean() { + let data = [100.0, 100.0, 100.0, 100.0] + let result = Sigma.rank(data, ties: "mean")! + XCTAssertEqual([2.5, 2.5, 2.5, 2.5], result) + } + + func testRanksTiesMin() { + let data = [100.0, 100.0, 100.0, 100.0] + let result = Sigma.rank(data, ties: "min")! + XCTAssertEqual([1.0, 1.0, 1.0, 1.0], result) + } + + func testRanksTiesMax() { + let data = [100.0, 100.0, 100.0, 100.0] + let result = Sigma.rank(data, ties: "max")! + XCTAssertEqual([4.0, 4.0, 4.0, 4.0], result) + } + + func testRanksTiesFirst() { + let data = [100.0, 100.0, 100.0, 100.0] + let result = Sigma.rank(data, ties: "first")! + XCTAssertEqual([1.0, 2.0, 3.0, 4.0], result) + } + + func testRanksTiesLast() { + let data = [100.0, 100.0, 100.0, 100.0] + let result = Sigma.rank(data, ties: "last")! + XCTAssertEqual([4.0, 3.0, 2.0, 1.0], result) + } + + func testRanksBlank() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0])! + XCTAssertEqual([1.5, 10.5, 4.0, 6.5, 4.0, 1.5, 4.0, 6.5, 8.5, 10.5, 8.5], result) + } + + func testRanksStart() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], start: 100)! + XCTAssertEqual([100.5, 109.5, 103.0, 105.5, 103.0, 100.5, 103.0, 105.5, 107.5, 109.5, 107.5], result) + } + + func testRanksMean() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], ties: "mean")! + XCTAssertEqual([1.5, 10.5, 4.0, 6.5, 4.0, 1.5, 4.0, 6.5, 8.5, 10.5, 8.5], result) + } + + func testRanksStartMean() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], start: 50, ties: "mean")! + XCTAssertEqual([50.5, 59.5, 53.0, 55.5, 53.0, 50.5, 53.0, 55.5, 57.5, 59.5, 57.5], result) + } + + func testRanksStartTiesMin() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], start: 25, ties: "min")! + XCTAssertEqual([25.0, 34.0, 27.0, 30.0, 27.0, 25.0, 27.0, 30.0, 32.0, 34.0, 32.0], result) + } + + func testRanksStartTiesMax() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], start: -99, ties: "max")! + XCTAssertEqual([-98.0, -89.0, -95.0, -93.0, -95.0, -98.0, -95.0, -93.0, -91.0, -89.0, -91.0], result) + } + + func testRanksStartTiesFirst() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], start: 0, ties: "first")! + XCTAssertEqual([0.0, 9.0, 2.0, 5.0, 3.0, 1.0, 4.0, 6.0, 7.0, 10.0, 8.0], result) + } + + func testRanksStartTiesLast() { + let result = Sigma.rank([1.0 ,6.0, 2.0 ,3.0 ,2.0 ,1.0 ,2.0 ,3.0 ,5.0 ,6.0 ,5.0], start: 2500, ties: "last")! + XCTAssertEqual([2501.0, 2510.0, 2504.0, 2506.0, 2503.0, 2500.0, 2502.0, 2505.0, 2508.0, 2509.0, 2507.0], result) + } + +} diff --git a/SigmaSwiftStatisticsTests/SkewnessKurtosisTests.swift b/SigmaSwiftStatisticsTests/SkewnessKurtosisTests.swift new file mode 100644 index 0000000..99dcfe7 --- /dev/null +++ b/SigmaSwiftStatisticsTests/SkewnessKurtosisTests.swift @@ -0,0 +1,91 @@ +import XCTest +import SigmaSwiftStatistics + +class SkewnessKurtosisTests: XCTestCase { + + // MARK: - testing normal array for skewness and then kurtosis + + func testSkewness_Norm() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + if let result = Sigma.skewness(data_array) { + XCTAssertEqualWithAccuracy(0.06416668605866518, result, accuracy: 0.000000000000001) + } + else { + XCTAssertNil(nil) + } + } + + func testKurtosis_Norm() { + let data_array = [0.52662978, 0.77362142, 0.57550701, 0.04158415, 0.03447811, + 0.08848505, 0.5236469 , 0.25523548, 0.89229563, 0.71272614, + 0.17107995, 0.26764894, 0.27308645, 0.38404429, 0.12755542, + 0.9856573 , 0.91394384, 0.50584635, 0.31623642, 0.13751698, + 0.68101821, 0.71853529, 0.66112074, 0.71656707, 0.35927775, + 0.76151524, 0.94317209, 0.01808385, 0.36550638, 0.9901121 , + 0.60259119, 0.62285146, 0.61310069, 0.55510847, 0.15929895, + 0.80369179, 0.26319102, 0.49952759, 0.34527164, 0.08919652, + 0.61979169, 0.43286263, 0.42874006, 0.1784381 , 0.51625026, + 0.74231264, 0.34506245, 0.70310094, 0.09531878, 0.02909812] + if let result = Sigma.kurtosis(data_array) { + XCTAssertEqualWithAccuracy(1.9473776246052905, result, accuracy: 0.00001) + } + else { + XCTAssertNil(nil) + } + } + + // MARK: - testing empty array for skewness and then kurtosis + + func testSkewness_Empty() { + let data_array: [Double] = [] + if let _ = Sigma.skewness(data_array) { + XCTFail() + } + else { + XCTAssertNil(nil) + } + } + + func testKurtosis_Empty() { + let data_array: [Double] = [] + if let _ = Sigma.kurtosis(data_array) { + XCTFail() + } + else { + XCTAssertNil(nil) + } + } + + // MARK: - testing array with single element for skewness and then kurtosis + + func testSkewness_Single() { + let data_array = [-99.999] + if let result = Sigma.skewness(data_array) { + XCTAssertEqual(0.0, result) + } + else { + XCTAssertNil(nil) + } + } + + func testKurtosis_Single() { + let data_array = [-99.999] + if let result = Sigma.kurtosis(data_array) { + XCTAssertEqual(0.0, result) + } + else { + XCTAssertNil(nil) + } + } + + +} diff --git a/SigmaSwiftStatisticsTests/UniqueValuesTests.swift b/SigmaSwiftStatisticsTests/UniqueValuesTests.swift new file mode 100644 index 0000000..16c2108 --- /dev/null +++ b/SigmaSwiftStatisticsTests/UniqueValuesTests.swift @@ -0,0 +1,36 @@ +import XCTest +import SigmaSwiftStatistics + +class UniqueValuesTests: XCTestCase { + // MARK: - Unique values + + func testEmptyArray() { + let result = Sigma.uniqueValues(values: []) + XCTAssertNil(result) + } + + func testArraySingle() { + let result = Sigma.uniqueValues(values: [-99]) + XCTAssertEqual([-99], result!) + } + + func testArrayHomogenous() { + let result = Sigma.uniqueValues(values: [55,55,55,55,55]) + XCTAssertEqual([55], result!) + } + + func testArrayPositive() { + let result = Sigma.uniqueValues(values: [2,5,6,5,6,2,5]) + XCTAssertEqual([2,5,6], result!) + } + + func testArrayNegative() { + let result = Sigma.uniqueValues(values: [-4,-5,-4,-5,-99,-5])?.sorted(by: <) + XCTAssertEqual([-99, -5,-4], result!) + } + + func testArrayMixed() { + let result = Sigma.uniqueValues(values: [55,-55,10,-10,-999, 10, -10, -55, 55, -999, 55])?.sorted(by: <) + XCTAssertEqual([-999, -55, -10, 10, 55], result!) + } +}