线性回归 - 加速Swift中的框架

时间:2015-04-16 12:38:10

标签: swift accelerate-framework

我在Stackoverflow的第一个问题......希望我的问题足够具体。

我在Swift中有一个数组,在某些日期有测量值。像:

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)

有些日子不见了,我只是没有进行测量......所有测量都应该在一条线上,或多或少。所以我想到了线性回归。我找到了Accelerate框架,但缺少文档,我找不到示例。

对于缺失的测量,我希望有一个功能,根据其他测量,输入缺失的一天和输出最佳猜测。

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

感谢您的帮助。 扬

2 个答案:

答案 0 :(得分:13)

我的回答并没有特别谈论加速框架,但我认为这个问题很有意思,并且我认为我会给它一个刺。从我收集到的内容中,您基本上希望创建一条最佳拟合线,并从中插入或推断出mW的更多值。为此,我使用了最小二乘法,详细信息如下:http://hotmath.com/hotmath_help/topics/line-of-best-fit.html并使用Swift在Playgrounds中实现:

//  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

在上面的代码ab中,请参阅网站上的以下公式:

aenter image description here

benter image description here

现在你可以创建一个使用最佳拟合线来插值/推断mW的函数:

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

并像这样使用它:

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

答案 1 :(得分:3)

如果你想在Swift中进行快速线性回归,我建议使用Upsurge框架。它提供了许多简单的函数来包装Accelerate库,因此您可以在iOS或OSX上获得SIMD的好处 无需担心vDSP调用的复杂性。

使用基础Upsurge函数进行线性回归很简单:

let meanx = mean(x)
let meany = mean(y)
let meanxy = mean(x * y)
let meanx_sqr = measq(x)

let slope = (meanx * meany - meanxy) / (meanx * meanx - meanx_sqr)
let intercept = meany - slope * meanx

这基本上是在 linregress 函数中实现的。

您可以将它与[Double]数组一起使用,其他类如RealArray(随Upsurge一起提供)或您自己的对象(如果它们可以暴露连续的内存)。

因此,满足您需求的脚本如下所示:

#!/usr/bin/env cato

import Upsurge

typealias PointTuple = (day: Double, mW:Double)

var myArray:[PointTuple] = []

myArray.append((0, 31.98))
myArray.append((1, 31.89))
myArray.append((2, 31.77))
myArray.append((4, 31.58))
myArray.append((6, 31.46))

let x = myArray.map { $0.day }
let y = myArray.map { $0.mW }

let (slope, intercept) = Upsurge.linregress(x, y)

func bG(day: Double) -> Double {
    return slope * day + intercept
}

(我在附加而不是使用文字,因为如果它的长度很大,你可能会以编程方式添加到数组中)

并且完全免责声明:我提供了linregress代码。我希望在未来的某个时刻也能增加决心的效率。