Skip to content
45 changes: 45 additions & 0 deletions SigmaSwiftStatistics/Frequencies.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
26 changes: 26 additions & 0 deletions SigmaSwiftStatistics/GeometricMean.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
28 changes: 28 additions & 0 deletions SigmaSwiftStatistics/HarmonicMean.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
48 changes: 48 additions & 0 deletions SigmaSwiftStatistics/Mode.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}


88 changes: 88 additions & 0 deletions SigmaSwiftStatistics/Ranks.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
33 changes: 33 additions & 0 deletions SigmaSwiftStatistics/UniqueValues.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
72 changes: 72 additions & 0 deletions SigmaSwiftStatisticsTests/FrequenciesTests.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
45 changes: 45 additions & 0 deletions SigmaSwiftStatisticsTests/GeometricMeanTests.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}

}
Loading