swift - 线性回归结果不如预期,经过简单测试
问题描述
我有一个从 Ray Wenderlich 借来的函数,用于对一系列点进行线性回归:
extension Array where Element == CGFloat {
// A closed form solution
fileprivate var average: CGFloat {
return self.reduce(0, +) / CGFloat(self.count)
}
}
extension CGFloat {
fileprivate static func multiply(_ a: [CGFloat], _ b: [CGFloat]) -> [CGFloat] {
return zip(a,b).map(*)
}
static func linearRegression(a: [CGFloat], b: [CGFloat]) -> (_ a: CGFloat) -> CGFloat {
let sum1 = CGFloat.multiply(b, a).average - a.average * b.average
let sum2 = CGFloat.multiply(a, a).average - pow(a.average, 2)
let slope = sum1 / sum2
let intercept = b.average - slope * a.average
return { x in intercept + slope * x }
}
}
我添加了一个简单的测试以确保它给我我期望的结果:
class CGFloatExtensionsTests: XCTestCase {
func testLinearRegression() {
let points = [
CGPoint(x: 1, y: 2),
CGPoint(x: 2, y: 1),
CGPoint(x: 3, y: 4),
CGPoint(x: 4, y: 3)
]
let linearRegression = CGFloat.linearRegression(a: points.map({$0.x}), b: points.map({$0.y}))
let y1 = linearRegression(1)
let y2 = linearRegression(3)
XCTAssertEqual(y1, 1, accuracy: 0.0001)
XCTAssertEqual(y2, 3, accuracy: 0.0001)
}
}
所以我平等地放置点,并期望线性回归线应该穿过这些点的中间。然而,这两个测试都失败了,第一个预期结果是1.6
,第二个是2.8
。
为了证明..蓝色是要点。绿色是我预期的线性回归线,黄色是实际的线性回归线。
我对此的期望/理解是否不正确?算法不正确吗?
解决方案
你的期望是错误的。简单的线性回归是直线
y = a * x + b
最小化观测 y 值和插值 y 值之差的平方和,即 (a, b) 确定为
sum( (a * xi + b - yi)^2, i=1,...,n)
尽可能小。为了你的价值观
(1, 2), (2, 1), (3, 4), (4, 3)
这是行
y = 0.6 x + 1
差的平方和为 3.2。对于这条线y = x
,平方差之和更大,即 4.0。
推荐阅读
- firebase - 发布 Flutter 应用后,Google 登录不起作用
- sql - 将固定数字按重量除以多行
- python - 埃拉托色尼筛法
- cross-validation - 如何在mlr中联合使用makeFeatSelWrapper和resample函数
- java - 使用另一个条目的值获取相互依赖的 Hashmap 的键
- c# - 在实现生产者/消费者模式时使用 Task.Yield 克服 ThreadPool 饥饿
- c++ - 是否可以检测是否声明了局部变量?
- gulp - gulp 在 zip 存档中添加文件夹
- database - 将文件从 drupal 7 迁移到 drupal 8
- arm - arm-none-eabi 全局初始化变量值不正确