线性回归的代码实现

发布时间 2023-11-18 15:57:12作者: 王哲MGG_AI

1.初始化步骤

import numpy as np
from utils.features import prepare_for_training

class LinearRegression:

    def __init__(self, data, labels, polynomial_degree=0, sinusoid_degree=0, normalize_data=True):
        """
        初始化线性回归模型对象。

        参数:
        - data: 输入数据集,每行表示一个样本,每列表示一个特征。
        - labels: 对应于输入数据集的标签。
        - polynomial_degree: 多项式特征的最高次数,默认为0,表示不使用多项式特征。
        - sinusoid_degree: 正弦特征的最高次数,默认为0,表示不使用正弦特征。
        - normalize_data: 是否对数据进行归一化,默认为True。

        初始化过程:
        1. 对输入数据进行预处理,包括多项式特征和正弦特征的处理,以及数据的归一化。
        2. 获取预处理后的数据、特征均值和标准差。
        3. 将预处理后的数据、标签,特征均值和标准差保存在对象的属性中。
        4. 获取预处理后数据的特征数量。
        5. 初始化参数矩阵theta为全零,其维度为(num_features, 1),其中num_features为特征数量。

        最终,LinearRegression对象被初始化为一个包含预处理信息和参数矩阵的线性回归模型。
        """
        # 1. 对数据进行预处理操作
        (data_processed,
         features_mean, 
         features_deviation) = prepare_for_training(data, polynomial_degree, sinusoid_degree, normalize_data=True)
         
        # 2. 将处理后的数据、标签以及预处理过程中得到的特征均值和标准差保存在对象的属性中
        self.data = data_processed
        self.labels = labels
        self.features_mean = features_mean
        self.features_deviation = features_deviation
        self.polynomial_degree = polynomial_degree
        self.sinusoid_degree = sinusoid_degree
        self.normalize_data = normalize_data
        
        # 3. 获取特征的数量,并初始化参数矩阵theta为全零
        num_features = self.data.shape[1]
        self.theta = np.zeros((num_features, 1))

2.模型的训练和梯度下降的过程

    def train(self, alpha, num_iterations=500):
        """
        训练模块,执行梯度下降。

        参数:
        - alpha: 学习率,控制每次参数更新的步长。
        - num_iterations: 迭代次数,默认为500。

        返回:
        - 训练后的参数矩阵theta
        - 每次迭代损失值的历史记录
        """
        # 执行梯度下降,获取损失值的历史记录
        cost_history = self.gradient_descent(alpha, num_iterations)
        # 返回训练后的参数矩阵和损失值的历史记录
        return self.theta, cost_history

    def gradient_descent(self, alpha, num_iterations):
        """
        实际迭代模块,会迭代num_iterations次。

        参数:
        - alpha: 学习率,控制每次参数更新的步长。
        - num_iterations: 迭代次数。

        返回:
        - 每次迭代损失值的历史记录
        """
        cost_history = []  # 用于存储每次迭代的损失值
        for _ in range(num_iterations):
            self.gradient_step(alpha)  # 执行一次梯度下降参数更新
            cost_history.append(self.cost_function(self.data, self.labels))  # 计算并记录当前损失值
        return cost_history

    def gradient_step(self, alpha):    
        """
        梯度下降参数更新计算方法,注意是矩阵运算。

        参数:
        - alpha: 学习率,控制每次参数更新的步长。
        """
        num_examples = self.data.shape[0]  # 样本数量
        prediction = LinearRegression.hypothesis(self.data, self.theta)  # 计算模型的预测值
        delta = prediction - self.labels  # 计算预测值与实际值的差异
        theta = self.theta  # 获取当前的参数矩阵
        theta = theta - alpha * (1/num_examples) * (np.dot(delta.T, self.data)).T  # 更新参数矩阵
        self.theta = theta  # 将更新后的参数矩阵保存在对象中

    def cost_function(self, data, labels):
        """
        损失计算方法。

        参数:
        - data: 输入数据集。
        - labels: 对应于输入数据集的标签。

        返回:
        - 损失值
        """
        num_examples = data.shape[0]  # 样本数量
        delta = LinearRegression.hypothesis(data, self.theta) - labels  # 计算预测值与实际值的差异
        cost = (1/2) * np.dot(delta.T, delta) / num_examples  # 计算损失值
        return cost[0][0]  # 返回损失值

这段代码包含了训练模块、实际迭代模块、梯度下降参数更新计算方法和损失计算方法。在 train 方法中,通过调用 gradient_descent 方法执行梯度下降,并返回训练后的参数矩阵和损失值的历史记录。在 gradient_descent 方法中,通过循环执行梯度下降的迭代,并记录每次迭代的损失值。在 gradient_step 方法中,实现了梯度下降的参数更新计算。在 cost_function 方法中,计算了损失值。

3.模型的训练和预测

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 导入自定义的线性回归模块
from linear_regression import LinearRegression

# 从CSV文件中读取数据
data = pd.read_csv('../data/world-happiness-report-2017.csv')

# 得到训练和测试数据
train_data = data.sample(frac=0.8)
test_data = data.drop(train_data.index)

# 选择输入和输出参数的列名
input_param_name = 'Economy..GDP.per.Capita.'
output_param_name = 'Happiness.Score'

# 提取训练数据和测试数据的特征和标签
x_train = train_data[[input_param_name]].values
y_train = train_data[[output_param_name]].values

x_test = test_data[input_param_name].values
y_test = test_data[output_param_name].values

# 绘制训练和测试数据的散点图
plt.scatter(x_train, y_train, label='Train data')
plt.scatter(x_test, y_test, label='Test data')
plt.xlabel(input_param_name)
plt.ylabel(output_param_name)
plt.title('Happiness vs. GDP per Capita')
plt.legend()
plt.show()

# 设置迭代次数和学习率
num_iterations = 500
learning_rate = 0.01

# 初始化线性回归模型并进行训练
linear_regression = LinearRegression(x_train, y_train)
(theta, cost_history) = linear_regression.train(learning_rate, num_iterations)

# 打印训练前和训练后的损失值
print('开始时的损失:', cost_history[0])
print('训练后的损失:', cost_history[-1])

# 绘制损失函数的迭代曲线
plt.plot(range(num_iterations), cost_history)
plt.xlabel('迭代次数')
plt.ylabel('损失值')
plt.title('梯度下降过程中损失函数的变化')
plt.show()

# 进行额外的预测
predictions_num = 100
x_predictions = np.linspace(x_train.min(), x_train.max(), predictions_num).reshape(predictions_num, 1)
y_predictions = linear_regression.predict(x_predictions)

# 绘制预测结果
plt.scatter(x_train, y_train, label='Train data')
plt.scatter(x_test, y_test, label='Test data')
plt.plot(x_predictions, y_predictions, 'r', label='Prediction')
plt.xlabel(input_param_name)
plt.ylabel(output_param_name)
plt.title('Happiness vs. GDP per Capita with Prediction')
plt.legend()
plt.show()