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

8

我在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
}

感谢您的帮助。 Jan
3个回答

18

我的回答并没有特别涉及加速框架,但我认为这个问题很有趣,所以我想试着回答一下。根据我的理解,您基本上是想创建一条最佳拟合线,并从中插值或外推更多的 mW 值。为了做到这一点,我使用了最小二乘法,在此处进行了详细说明:http://hotmath.com/hotmath_help/topics/line-of-best-fit.html ,并在Playgrounds中使用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
在上面的代码中,ab指的是来自网站的以下公式: a: enter image description here b: enter 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

非常感谢您的代码(以及对我的问题的编辑),ABakerSmith!我非常满意...顺便说一句,正如我所说,我是Stackoverflow的新手...我应该为您投票以获得另一个徽章吗?很乐意... :-) - arakweker
太棒了,我很高兴能帮到你!如果你觉得某个答案解决了你的问题,你可以点击左边的勾号将其标记为正确答案。你也可以给问题的答案点赞,但我相信你需要15个积分才能这样做。 - ABakerSmith
顺便说一下,欢迎来到 Stack Overflow! - ABakerSmith
在Swift中,可以使用多项式回归来实现n次方程的拟合吗? - user13138159

4
如果您想在Swift中进行快速线性回归,我建议使用Upsurge框架。它提供了许多简单的函数,包装了加速库,因此您可以在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]数组、其他类(例如带有Upsurge的RealArray)或自己的对象一起使用,只要它们可以公开连续的内存。
因此,符合您需求的脚本如下:
#!/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代码。我希望在将来某个时候还能添加确定系数。


0

要估算不同点之间的值,您还可以使用来自 SpriteKitSKKeyframeSequence https://developer.apple.com/documentation/spritekit/skinterpolationmode/spline

import SpriteKit

let sequence = SKKeyframeSequence(keyframeValues: [0, 20, 40, 60, 80, 100], times: [64, 128, 256, 512, 1024, 2048])
sequence.interpolationMode = .spline // .linear, .step

let estimatedValue = sequence.sample(atTime: CGFloat(1500)) as! Double // 1500 is the value you want to estimate
print(estimatedValue)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接