7

I am looking at Accelerate to compute mean and standard deviation of arrays in Swift.

I can do the mean. How do I do the standard deviation?

let rr: [Double] = [ 18.0, 21.0, 41.0, 42.0, 48.0, 50.0, 55.0, 90.0 ]

var mn: Double = 0.0

vDSP_meanvD(rr, 1, &mn, vDSP_Length(rr.count))

print(mn) // prints correct mean as 45.6250

// Standard Deviation should be 22.3155
Pat
  • 325
  • 1
  • 12
  • I think you can compute it from the mean and the "mean square" (vDSP_measqvD) ... – Martin R Feb 09 '17 at 09:52
  • Thanks Martin! Could you please show me how the vDSP_measqvD works? The argument has an asterisk (*). I am still confused about using these. – Pat Feb 09 '17 at 09:55
  • vDSP_measqvD has exactly the same interface as vDSP_meanvD. – Martin R Feb 09 '17 at 09:56
  • Ok, I will try. – Pat Feb 09 '17 at 09:58
  • One thing I might recommend is to benchmark whether Accelerate makes a difference for your data set. I once put a fair bit of effort into optimizing Swift with Accelerate only to find that the improvement in performance was negligible from using `map` and `reduce` after compiler optimizations. – Scott H Feb 09 '17 at 10:06
  • 1
    @ScottH: That is a good point. I made different experiences: Here http://stackoverflow.com/a/41806438/1187415 the Accelerate method was not faster than an explicit loop. Here http://stackoverflow.com/a/42129847/1187415 it was faster by a factor of 5. It probably depends on the hardware as well. – Martin R Feb 09 '17 at 10:15

2 Answers2

15

You can compute the standard deviation from the mean value and the mean square value (compare https://en.wikipedia.org/wiki/Standard_deviation#Identities_and_mathematical_properties and https://en.wikipedia.org/wiki/Algebraic_formula_for_the_variance):

import Accelerate

let rr: [Double] = [ 18.0, 21.0, 41.0, 42.0, 48.0, 50.0, 55.0, 90.0 ]

var mn: Double = 0.0 // mean value
vDSP_meanvD(rr, 1, &mn, vDSP_Length(rr.count))

var ms: Double = 0.0 // mean square value
vDSP_measqvD(rr, 1, &ms, vDSP_Length(rr.count))

let sddev = sqrt(ms - mn * mn) * sqrt(Double(rr.count)/Double(rr.count - 1))

print(mn, sddev)
// 45.625 22.315513501982

Alternatively (for iOS 9.0 and later or macOS 10.11 and later), use vDSP_normalizeD:

var mn = 0.0
var sddev = 0.0
vDSP_normalizeD(rr, 1, nil, 1, &mn, &sddev, vDSP_Length(rr.count))
sddev *= sqrt(Double(rr.count)/Double(rr.count - 1))

print(mn, sddev)
// 45.625 22.315513501982
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
4

an add-on for @Martin R's answer: There is also a vDSP_normalize function for Float/single precision.

func vDSP_normalize(UnsafePointer<Float>, vDSP_Stride, UnsafeMutablePointer<Float>?, vDSP_Stride, UnsafeMutablePointer<Float>, UnsafeMutablePointer<Float>, vDSP_Length)
//Compute mean and standard deviation and then calculate new elements to have a zero mean and a unit standard deviation. Single precision.

func vDSP_normalizeD(UnsafePointer<Double>, vDSP_Stride, UnsafeMutablePointer<Double>?, vDSP_Stride, UnsafeMutablePointer<Double>, UnsafeMutablePointer<Double>, vDSP_Length)
//Compute mean and standard deviation and then calculate new elements to have a zero mean and a unit standard deviation. Double precision.
Lynne
  • 454
  • 7
  • 16