Go语言机器学习实战:回归分析与预测模型

在机器学习领域,回归分析是一种用于预测连续数值输出的监督学习方法。本文将深入探讨如何使用Go语言实现多种回归算法,并构建实用的预测模型。

文章总体概览信息图

一、回归分析概述

回归分析是统计学和机器学习中的核心技术,用于建立自变量和因变量之间的关系模型。常见的回归类型包括:

  • 线性回归:最简单的回归模型,假设特征与目标之间存在线性关系
  • 多元线性回归:多个特征共同影响目标变量
  • 多项式回归:处理非线性关系
  • 岭回归:带有L2正则化的线性回归,防止过拟合
  • Lasso回归:带有L1正则化的线性回归,可实现特征选择

二、Go语言线性回归实现

2.1 简单线性回归

简单线性回归假设输入特征x和输出y之间存在线性关系:y = wx + b

package main

import (
    "fmt"
    "math"
)

type LinearRegression struct {
    weight     float64
    bias       float64
    learningRate float64
}

func NewLinearRegression(lr float64) *LinearRegression {
    return &LinearRegression{
        weight:       0,
        bias:         0,
        learningRate: lr,
    }
}

func (lr *LinearRegression) Predict(x float64) float64 {
    return lr.weight*x + lr.bias
}

func (lr *LinearRegression) Train(x, y []float64, epochs int) {
    n := float64(len(x))
    
    for epoch := 0; epoch < epochs; epoch++ {
        // 前向传播
        var predictions []float64
        for _, xi := range x {
            predictions = append(predictions, lr.Predict(xi))
        }
        
        // 计算梯度
        var dw, db float64
        for i := 0; i < len(x); i++ {
            error := predictions[i] - y[i]
            dw += error * x[i]
            db += error
        }
        dw /= n
        db /= n
        
        // 更新参数
        lr.weight -= lr.learningRate * dw
        lr.bias -= lr.learningRate * db
        
        // 计算损失
        if epoch%100 == 0 {
            loss := lr.MSE(x, y)
            fmt.Printf("Epoch %d: MSE = %.4f\n", epoch, loss)
        }
    }
}

func (lr *LinearRegression) MSE(x, y []float64) float64 {
    var sumErr float64
    for i := 0; i < len(x); i++ {
        pred := lr.Predict(x[i])
        sumErr += math.Pow(pred-y[i], 2)
    }
    return sumErr / float64(len(x))
}

func main() {
    // 示例数据:房屋面积与价格
    x := []float64{50, 60, 70, 80, 90, 100, 110, 120}
    y := []float64{150, 180, 200, 230, 250, 280, 300, 330}
    
    model := NewLinearRegression(0.0001)
    model.Train(x, y, 1000)
    
    fmt.Printf("训练完成!权重=%.4f, 偏置=%.4f\n", model.weight, model.bias)
    
    // 预测
    testX := 130.0
    fmt.Printf("面积%.0f平方米的房屋价格预测:%.2f万元\n", testX, model.Predict(testX))
}

2.2 多元线性回归

当有多个特征影响目标变量时,需要使用多元线性回归:

type MultiLinearRegression struct {
    weights    []float64
    bias       float64
    learningRate float64
}

func NewMultiLinearRegression(lr float64, featureNum int) *MultiLinearRegression {
    return &MultiLinearRegression{
        weights:      make([]float64, featureNum),
        bias:         0,
        learningRate: lr,
    }
}

func (mlr *MultiLinearRegression) Predict(x []float64) float64 {
    var result float64
    for i, w := range mlr.weights {
        result += w * x[i]
    }
    return result + mlr.bias
}

func (mlr *MultiLinearRegression) Train(X [][]float64, y []float64, epochs int) {
    n := float64(len(X))
    
    for epoch := 0; epoch < epochs; epoch++ {
        // 计算梯度
        dW := make([]float64, len(mlr.weights))
        dB := 0.0
        
        for i := 0; i < len(X); i++ {
            pred := mlr.Predict(X[i])
            error := pred - y[i]
            
            for j := 0; j < len(mlr.weights); j++ {
                dW[j] += error * X[i][j]
            }
            dB += error
        }
        
        // 平均梯度
        for j := 0; j < len(mlr.weights); j++ {
            dW[j] /= n
        }
        dB /= n
        
        // 更新参数
        for j := 0; j < len(mlr.weights); j++ {
            mlr.weights[j] -= mlr.learningRate * dW[j]
        }
        mlr.bias -= mlr.learningRate * dB
    }
}

三、多项式回归实现

多项式回归可以处理非线性关系,通过将特征进行多项式变换:

type PolynomialRegression struct {
    weights    []float64
    degree     int
}

func NewPolynomialRegression(degree int) *PolynomialRegression {
    return &PolynomialRegression{
        weights: make([]float64, degree+1),
        degree:  degree,
    }
}

func (pr *PolynomialRegression) transform(x float64) []float64 {
    features := make([]float64, pr.degree+1)
    features[0] = 1
    for i := 1; i <= pr.degree; i++ {
        features[i] = math.Pow(x, float64(i))
    }
    return features
}

func (pr *PolynomialRegression) Predict(x float64) float64 {
    features := pr.transform(x)
    var result float64
    for i, w := range pr.weights {
        result += w * features[i]
    }
    return result
}

func (pr *PolynomialRegression) Train(x, y []float64, lr float64, epochs int) {
    n := float64(len(x))
    
    for epoch := 0; epoch < epochs; epoch++ {
        gradients := make([]float64, len(pr.weights))
        
        for i := 0; i < len(x); i++ {
            features := pr.transform(x[i])
            pred := pr.Predict(x[i])
            error := pred - y[i]
            
            for j := 0; j < len(pr.weights); j++ {
                gradients[j] += error * features[j]
            }
        }
        
        for j := 0; j < len(pr.weights); j++ {
            gradients[j] /= n
            pr.weights[j] -= lr * gradients[j]
        }
    }
}

四、正则化回归

4.1 岭回归(L2正则化)

type RidgeRegression struct {
    weights    []float64
    bias       float64
    lambda     float64
}

func (rr *RidgeRegression) Train(X [][]float64, y []float64, lr, lambda float64, epochs int) {
    rr.lambda = lambda
    n := float64(len(X))
    
    for epoch := 0; epoch < epochs; epoch++ {
        dW := make([]float64, len(rr.weights))
        dB := 0.0
        
        for i := 0; i < len(X); i++ {
            pred := rr.Predict(X[i])
            error := pred - y[i]
            
            for j := 0; j < len(rr.weights); j++ {
                dW[j] += error * X[i][j]
            }
            dB += error
        }
        
        for j := 0; j < len(rr.weights); j++ {
            dW[j] = dW[j]/n + lambda*rr.weights[j]
            rr.weights[j] -= lr * dW[j]
        }
        dB /= n
        rr.bias -= lr * dB
    }
}

4.2 Lasso回归(L1正则化)

type LassoRegression struct {
    weights    []float64
    bias       float64
    lambda     float64
}

func (lr *LassoRegression) Train(X [][]float64, y []float64, lr, lambda float64, epochs int) {
    lr.lambda = lambda
    n := float64(len(X))
    
    for epoch := 0; epoch < epochs; epoch++ {
        dW := make([]float64, len(lr.weights))
        dB := 0.0
        
        for i := 0; i < len(X); i++ {
            pred := lr.Predict(X[i])
            error := pred - y[i]
            
            for j := 0; j < len(lr.weights); j++ {
                dW[j] += error * X[i][j]
            }
            dB += error
        }
        
        for j := 0; j < len(lr.weights); j++ {
            dW[j] = dW[j]/n + lambda*sign(lr.weights[j])
            lr.weights[j] -= lr * dW[j]
        }
        dB /= n
        lr.bias -= lr * dB
    }
}

func sign(x float64) float64 {
    if x > 0 {
        return 1
    } else if x < 0 {
        return -1
    }
    return 0
}

五、模型评估指标

回归模型的评估需要使用专门的指标:

func MeanAbsoluteError(yTrue, yPred []float64) float64 {
    var sum float64
    for i := 0; i < len(yTrue); i++ {
        sum += math.Abs(yTrue[i] - yPred[i])
    }
    return sum / float64(len(yTrue))
}

func MeanSquaredError(yTrue, yPred []float64) float64 {
    var sum float64
    for i := 0; i < len(yTrue); i++ {
        sum += math.Pow(yTrue[i]-yPred[i], 2)
    }
    return sum / float64(len(yTrue))
}

func RootMeanSquaredError(yTrue, yPred []float64) float64 {
    return math.Sqrt(MeanSquaredError(yTrue, yPred))
}

func R2Score(yTrue, yPred []float64) float64 {
    var mean, ssTot, ssRes float64
    for _, y := range yTrue {
        mean += y
    }
    mean /= float64(len(yTrue))
    
    for i := 0; i < len(yTrue); i++ {
        ssTot += math.Pow(yTrue[i]-mean, 2)
        ssRes += math.Pow(yTrue[i]-yPred[i], 2)
    }
    
    return 1 - ssRes/ssTot
}

六、完整示例:波士顿房价预测

func main() {
    // 加载波士顿房价数据集(简化版)
    X := [][]float64{
        {6.575, 4.98},   // RM(房间数), LSTAT(低收入比例)
        {6.421, 9.14},
        {7.185, 4.03},
        {6.998, 2.94},
        {7.147, 5.33},
    }
    y := []float64{24.0, 21.6, 34.7, 33.4, 36.2}
    
    model := NewMultiLinearRegression(0.0001, 2)
    model.Train(X, y, 10000)
    
    fmt.Println("模型权重:", model.weights)
    fmt.Println("模型偏置:", model.bias)
    
    // 预测
    testX := []float64{7.5, 3.5}
    pred := model.Predict(testX)
    fmt.Printf("预测房价: %.2f\n", pred)
}

七、总结

通过本文的学习,我们掌握了:

  1. 线性回归的基本原理和Go语言实现
  2. 多元线性回归处理多特征场景
  3. 多项式回归处理非线性关系
  4. 正则化回归(岭回归和Lasso回归)防止过拟合
  5. 常用的回归模型评估指标

Go语言的简洁语法和高性能特性使其成为机器学习领域的优秀选择。结合gonum等数值计算库,可以构建更复杂的机器学习系统。下一篇文章将介绍Go语言中的聚类算法实现。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐