Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features/harmonic mean #12

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
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
}
}
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)
}
}

}
45 changes: 45 additions & 0 deletions SigmaSwiftStatisticsTests/HarmonicMeanTests.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}

}
Loading