【问题标题】:Linear regression - accelerate framework in Swift线性回归 - 在 Swift 中加速框架
【发布时间】:2015-04-16 12:38:10
【问题描述】:

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

感谢您的帮助。 一月

【问题讨论】:

    标签: swift accelerate-framework


    【解决方案1】:

    我的回答并没有专门讨论 Accelerate 框架,但我认为这个问题很有趣,并认为我会试一试。从我收集到的信息来看,您基本上是在寻找一条最合适的线,并从中插值或推断出更多 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:

    b:

    现在您可以创建使用最佳拟合线插入/外推mW的函数:

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

    然后像这样使用它:

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

    【讨论】:

    • 非常感谢您的代码(以及您对我的问题的编辑),ABakerSmith!我对此感到非常满意...顺便说一句,正如我所说我是 Stackoverflow 的新手...我应该为您投票给另一个徽章吗?很乐意... :-)
    • 太棒了,我很高兴它有帮助!如果您认为某个答案解决了您的问题,您可以按左侧的复选标记将其标记为正确。您也可以对问题的答案进行投票,但我认为您需要 15 分。
    • 顺便欢迎来到 Stack Overflow!
    • 在 Swift 中,n 次多项式回归也能实现同样的效果吗?
    【解决方案2】:

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

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

    让 meanx = mean(x) 让平均值 = 平均值(y) 让 meanxy = mean(x * y) 让 meanx_sqr = measq(x) 让斜率 = (meanx * meany - meanxy) / (meanx * meanx - meanx_sqr) 让截距 = meany - 斜率 * meanx

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

    您可以将它与 [Double] 数组、其他类(例如 RealArray(Upsurge 附带))或您自己的对象(如果它们可以公开连续内存)一起使用。

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

    #!/usr/bin/env 卡托 进口热潮 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)) 让 x = myArray.map { $0.day } 让 y = myArray.map { $0.mW } 让(斜率,截距)= Upsurge.linregress(x, y) func bG(day: Double) -> Double { 返回斜率 * 天 + 截距 }

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

    和完整的免责声明:我贡献了 linregress 代码。我希望在未来的某个时候也增加确定系数。

    【讨论】:

      猜你喜欢
      • 2021-06-04
      • 2019-04-12
      • 2015-06-30
      • 2012-10-02
      • 2017-01-27
      • 2020-05-04
      • 1970-01-01
      • 2020-03-13
      • 2021-01-14
      相关资源
      最近更新 更多