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):
        """
        1.对数据进行预处理操作
        2.先得到所有的特征个数
        3.初始化参数矩阵
        """
        (data_processed,
         features_mean,
         features_deviation)  = prepare_for_training(data, polynomial_degree, sinusoid_degree,normalize_data=True)

        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

        num_features = self.data.shape[1]
        self.theta = np.zeros((num_features,1))

    def train(self,alpha,num_iterations = 500):
        """
                    训练模块,执行梯度下降
        """
        cost_history = self.gradient_descent(alpha,num_iterations)
        return self.theta,cost_history

    def gradient_descent(self,alpha,num_iterations):
        """
                    实际迭代模块,会迭代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):
        """
                    梯度下降参数更新计算方法,注意是矩阵运算
        """
        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):
        """
                    损失计算方法
        """
        num_examples = data.shape[0]
        delta = LinearRegression.hypothesis(self.data,self.theta) - labels
        cost = (1/2)*np.dot(delta.T,delta)/num_examples
        return cost[0][0]



    @staticmethod
    def hypothesis(data,theta):
        predictions = np.dot(data,theta)
        return predictions

    def get_cost(self,data,labels):
        data_processed = prepare_for_training(data,
         self.polynomial_degree,
         self.sinusoid_degree,
         self.normalize_data
         )[0]

        return self.cost_function(data_processed,labels)
    def predict(self,data):
        """
                    用训练的参数模型,与预测得到回归值结果
        """
        data_processed = prepare_for_training(data,
         self.polynomial_degree,
         self.sinusoid_degree,
         self.normalize_data
         )[0]

        predictions = LinearRegression.hypothesis(data_processed,self.theta)

        return predictions

import numpy as np是Python语法的一部分,它用于导入名为NumPy的库,并将其命名为np。导入NumPy库后,可以使用np来访问库中的各种功能和对象。通过导入NumPy库,我们可以使用NumPy的多维数组对象、数学函数、数组操作等功能来进行科学计算和数据处理。使用np作为别名是为了方便在代码中使用NumPy库的函数和对象,可以通过np.函数名的方式来调用相应的功能。例如,如果要创建一个NumPy的多维数组,可以使用np.array()函数;如果要进行矩阵乘法运算,可以使用np.dot()函数;如果要计算数组的平均值,可以使用np.mean()函数,等等。

from utils.features import prepare_for_training 是Python语法的一部分,它用于从名为utils.features的模块中导入prepare_for_training函数。在这段代码中,prepare_for_training函数被用于数据预处理的操作。通过导入该函数,我们可以在当前的Python程序中使用prepare_for_training函数,以便对数据进行预处理,无需在代码中使用完整的模块路径来引用该函数。例如,如果要对数据进行预处理,可以使用prepare_for_training(data, polynomial_degree, sinusoid_degree, normalize_data=True)来调用prepare_for_training函数,并传递相应的参数。总之,from utils.features import prepare_for_training语句是将utils.features模块中的prepare_for_training函数导入到当前的Python程序中的一种方式。这样我们可以直接使用该函数,简化代码并方便地进行数据预处理操作。

__init__ 方法是 Python 类中的特殊方法,用于初始化类的实例对象。在这段代码中,__init__ 方法被用于初始化 LinearRegression 类的实例对象。

解释 __init__ 方法的代码:

  • data: 输入的数据。

  • labels: 数据对应的标签。

  • polynomial_degree: 多项式特征的最高次数,默认为0,表示不使用多项式特征。

  • sinusoid_degree: 正弦函数特征的最高次数,默认为0,表示不使用正弦函数特征。

  • normalize_data: 是否对数据进行归一化处理,默认为 True

__init__ 方法中的操作:

  • 调用 prepare_for_training 函数对输入数据进行预处理,并获取预处理后的数据、特征均值和特征标准差。预处理操作包括多项式特征和正弦函数特征的生成,以及数据归一化处理。

  • 将预处理后的数据存储在 self.data 属性中。

  • 将输入的标签存储在 self.labels 属性中。

  • 存储特征均值和特征标准差在 self.features_meanself.features_deviation 属性中。

  • 存储多项式特征的最高次数和正弦函数特征的最高次数在 self.polynomial_degreeself.sinusoid_degree 属性中。

  • 存储是否进行数据归一化处理的标志在 self.normalize_data 属性中。

  • 获取数据的特征个数,并将其存储在 num_features 变量中。

  • 初始化参数矩阵 self.theta 为一个形状为 (num_features, 1) 的零矩阵。

通过这个初始化过程,可以为 LinearRegression 类的实例对象提供必要的属性和初始值,以便后续的训练和预测操作。

 (data_processed,
          features_mean,
          features_deviation)  = prepare_for_training(data, polynomial_degree, sinusoid_degree,normalize_data=True)           

这行代码使用了元组解包(tuple unpacking)的方式,将 prepare_for_training 函数的返回值分别赋值给 data_processedfeatures_meanfeatures_deviation 这三个变量。具体地,prepare_for_training 函数被调用,并传入参数 datapolynomial_degreesinusoid_degreenormalize_data=True。该函数的返回值是一个包含三个元素的元组,分别是经过预处理后的数据 data_processed、特征均值 features_mean 和特征标准差 features_deviation。通过元组解包的方式,将返回的元组按顺序赋值给对应的变量。这样做的目的是为了方便后续在 __init__ 方法中使用这些预处理结果,例如将预处理后的数据存储在 self.data 属性中,将特征均值存储在 self.features_mean 属性中,将特征标准差存储在 self.features_deviation 属性中,以便在训练和预测过程中使用。

在Python中,self 是一个约定俗成的参数名,用于表示类的实例对象自身。它在类的方法中作为第一个参数传递,表示对当前实例对象的引用。

self 的作用主要有以下几个方面:

  1. 访问实例属性和方法: 使用 self 可以访问类的实例对象中定义的属性和方法。通过 self.attribute_name 可以访问实例对象的属性,通过 self.method_name() 可以调用实例对象的方法。

  2. 区分实例变量和局部变量: 在方法内部,如果存在与实例属性同名的局部变量,使用 self 可以明确指定要访问的是实例属性而不是局部变量。例如,self.data 表示访问实例对象的 data 属性,而不是方法内部的局部变量。

  3. 在类的方法中传递实例对象: 当定义类的方法时,可以使用 self 作为参数,在方法调用时将类的实例对象传递给方法。这样可以在方法中操作和访问实例对象的属性和方法。

总之,self 是一个特殊的参数名,代表当前实例对象自身,可以用于访问实例属性和方法,以及区分实例属性和局部变量。它在类的方法中起到非常重要的作用,使得我们可以在类的内部操作和访问实例对象的成员。

在上述代码中,self 是一个特殊的参数,它代表了类的实例对象。通过使用 self,可以访问和操作类的属性和方法。在类的方法中,使用 self 可以引用类的实例对象的属性和方法。通过 self,可以在方法内部访问和修改类的实例变量,并且在不同的方法之间共享数据。具体到上述代码中,self 在以下几个地方发挥作用:

  1. __init__ 方法中的 self.dataself.labelsself.features_meanself.features_deviationself.polynomial_degreeself.sinusoid_degreeself.normalize_dataself.theta 都是类的实例变量。通过 self 可以将传入的参数值存储为类的实例变量,以供其他方法使用。

  2. 在类的其他方法中,例如 traingradient_descentgradient_stepcost_functionpredict 方法中,使用 self 可以访问和操作 __init__ 方法中创建的实例变量。例如,self.data 可以用于获取预处理后的数据,self.theta 可以用于更新参数矩阵,self.labels 可以用于计算损失函数等。

通过使用 self,类的方法可以访问类的实例变量,实现类内部的数据共享和操作。这样可以更方便地组织和管理代码,并提供更灵活的数据访问方式。

train 方法是用于训练模型的函数。下面是对该方法的解释:

  • selfself 表示类的实例对象,通过它可以访问类的属性和方法。

  • alpha:学习率(learning rate),用于控制参数更新的步长。

  • num_iterations:迭代次数,默认为 500。

该方法的主要步骤如下:

  1. 调用 gradient_descent 方法执行梯度下降,并将返回的损失历史存储在 cost_history 变量中。

  2. 返回训练得到的参数矩阵 self.theta 和损失历史 cost_history

该方法的作用是执行梯度下降算法来训练模型,通过迭代更新参数矩阵 self.theta,使得模型的预测结果与实际标签之间的误差逐渐减小。在每次迭代中,调用 gradient_descent 方法更新参数,并计算当前的损失值。最终,返回训练得到的参数矩阵和损失历史,以供后续分析和使用。请注意,该方法依赖于 gradient_descent 方法的实现,该方法在后续的代码中定义了梯度下降的具体实现逻辑。

gradient_descent 方法是执行实际的梯度下降迭代的函数。下面是对该方法的解释:

  • selfself 表示类的实例对象,通过它可以访问类的属性和方法。

  • alpha:学习率(learning rate),用于控制参数更新的步长。

  • num_iterations:迭代次数。

该方法的主要步骤如下:

  1. 创建一个空列表 cost_history,用于存储每次迭代后的损失值。

  2. 使用 for 循环迭代 num_iterations 次,表示进行指定次数的迭代。

  3. 在每次迭代中,调用 self.gradient_step(alpha) 方法执行一次梯度下降参数更新。

  4. 调用 self.cost_function(self.data, self.labels) 方法计算当前迭代的损失值。

  5. 将计算得到的损失值添加到 cost_history 列表中。

  6. 完成所有迭代后,返回存储着每次迭代损失值的 cost_history 列表。

该方法的作用是执行梯度下降算法的实际迭代过程,通过多次迭代更新参数并计算损失值,以获取模型的最优参数。在每次迭代中,调用 gradient_step 方法更新参数,并调用 cost_function 方法计算当前的损失值。最终,返回包含每次迭代损失值的列表,以供后续分析和使用。请注意,该方法依赖于 gradient_step 方法和 cost_function 方法的实现,它们在后续的代码中定义了梯度下降参数更新和损失计算的具体逻辑。

cost_function 方法用于计算损失函数的值。下面是对该方法的解释:

  • selfself 表示类的实例对象,通过它可以访问类的属性和方法。

  • data:输入数据。

  • labels:实际标签。

该方法的主要步骤如下:

  1. 获取输入数据的样本数(num_examples)。

  2. 使用模型的预测结果与实际标签之间的差值计算误差(delta),其中 LinearRegression.hypothesis(self.data, self.theta) 表示模型的预测值。

  3. 计算损失函数的值,使用公式 (1/2) * np.dot(delta.T, delta) / num_examples,其中 np.dot() 表示矩阵的点积。

  4. 返回计算得到的损失函数的值 cost[0][0]

该方法的作用是根据模型的预测值和实际标签之间的差异来计算损失函数的值,用于衡量模型的预测准确度和误差程度。通过对所有样本进行计算,可以得到整体的损失值。最终,返回计算得到的损失函数的值,以供后续分析和使用。请注意,该方法依赖于 LinearRegression.hypothesis 方法的实现,它在后续的代码中定义了模型的预测逻辑。

hypothesisget_costpredict。下面是对它们的解释:

  1. hypothesis 方法是一个静态方法(@staticmethod),用于计算线性回归模型的预测结果。下面是对该方法的解释:

    • data:输入数据。

    • theta:模型的参数。

    • 该方法通过执行矩阵乘法 np.dot(data, theta),将输入数据与参数进行乘积运算,得到预测结果。

    • 返回预测结果 predictions

  2. get_cost 方法用于计算给定数据和标签的损失函数值。下面是对该方法的解释:

    • data:输入数据。

    • labels:实际标签。

    • 在该方法内部,首先对输入数据进行预处理操作,使用 prepare_for_training 函数进行处理,并获取处理后的数据 data_processed

    • 然后,调用 self.cost_function(data_processed, labels) 方法,使用处理后的数据和标签计算损失函数的值。

    • 返回计算得到的损失函数值。

  3. predict 方法用于对给定数据进行预测,即使用训练好的模型参数对数据进行回归预测。下面是对该方法的解释:

    • data:输入数据。

    • 在该方法内部,首先对输入数据进行预处理操作,使用 prepare_for_training 函数进行处理,并获取处理后的数据 data_processed

    • 然后,调用 LinearRegression.hypothesis(data_processed, self.theta) 方法,使用处理后的数据和模型的参数进行预测,得到预测结果。

    • 返回预测结果 predictions

这些方法的作用是在训练好的线性回归模型中进行预测和损失计算。hypothesis 方法用于计算预测结果,get_cost 方法用于计算给定数据和标签的损失函数值,predict 方法用于对给定数据进行回归预测。这些方法依赖于其他函数和类的实现,例如 prepare_for_training 函数和 cost_function 方法。

hypothesis 方法作为一个静态方法的作用是计算线性回归模型的预测结果。静态方法是与类相关联的方法,但不需要通过类的实例进行调用,可以直接通过类名调用。

在上述代码中,hypothesis 方法接受两个参数:datatheta。它执行矩阵乘法操作 np.dot(data, theta),将输入数据 data 与模型的参数 theta 进行乘积运算,得到线性回归模型的预测结果。预测结果被存储在变predictions 中,并作为方法的返回值进行返回。由于 hypothesis 方法不依赖于类的实例属性,它可以在没有创建类的实例的情况下被直接调用。这使得它可以在其他方法中或与其他类的方法共享,而无需实例化类对象。静态方法通常用于具有通用功能的操作,可以在类的多个实例之间共享和重复使用。在这个特定的案例中,静态方法 hypothesis 用于计算线性回归模型的预测结果,可以在类内的其他方法中调用或通过类名直接调用。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐