我有一个函数borrowed from 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
。
要演示..蓝色是要点。绿色是我预期的线性回归线,而黄色是实际的线性回归线。
我对此的期望/理解不正确吗?算法不正确吗?
答案 0 :(得分:2)
您的期望是错误的。 simple linear regression是一行
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。