Search code examples
swiftaccelerate-framework

Linear regression - accelerate framework in Swift


My first question here at Stackoverflow... hope my question is specific enough.

I have an array in Swift with measurements at certain dates. Like:

var myArray:[(day: Int, mW: Double)] = []
myArray.append(day:0, mW: 31.98)
myArray.append(day:1, mW: 31.89)
myArray.append(day:2, mW: 31.77)
myArray.append(day:4, mW: 31.58)
myArray.append(day:6, mW: 31.46)

Some days are missing, I just didn't take a measurement... All measurements should be on a line, more or less. So I thought about linear regression. I found the Accelerate framework, but the documentation is missing and I can't find examples.

For the missing measurements I would like to have a function, with as input a missing day and as output a best guess, based on the other measurements.

func bG(day: Int) -> Double {
    return // return best guess for measurement
}

Thanks for helping out. Jan


Solution

  • My answer doesn't specifically talk about the Accelerate Framework, however I thought the question was interesting and thought I'd give it a stab. From what I gather you're basically looking to create a line of best fit and interpolate or extrapolate more values of mW from that. To do that I used the Least Square Method, detailed here: http://hotmath.com/hotmath_help/topics/line-of-best-fit.html and implemented this in Playgrounds using Swift:

    //  The typealias allows us to use '$X.day' and '$X.mW',
    //  instead of '$X.0' and '$X.1' in the following closures.
    typealias PointTuple = (day: Double, mW: Double)
    
    //  The days are the values on the x-axis.
    //  mW is the value on the y-axis.
    let points: [PointTuple] = [(0.0, 31.98),
                                (1.0, 31.89),
                                (2.0, 31.77),
                                (4.0, 31.58),
                                (6.0, 31.46)]
    
    // When using reduce, $0 is the current total.
    let meanDays = points.reduce(0) { $0 + $1.day } / Double(points.count)
    let meanMW   = points.reduce(0) { $0 + $1.mW  } / Double(points.count)
    
    let a = points.reduce(0) { $0 + ($1.day - meanDays) * ($1.mW - meanMW) }
    let b = points.reduce(0) { $0 + pow($1.day - meanDays, 2) }
    
    // The equation of a straight line is: y = mx + c
    // Where m is the gradient and c is the y intercept.
    let m = a / b
    let c = meanMW - m * meanDays
    

    In the code above a and b refer to the following formula from the website:

    a: enter image description here

    b:enter image description here

    Now you can create the function which uses the line of best fit to interpolate/extrapolate mW:

    func bG(day: Double) -> Double {
        return m * day + c
    }
    

    And use it like so:

    bG(3) // 31.70
    bG(5) // 31.52
    bG(7) // 31.35