【PaddlePaddle】基础理论教程 – 机器学习理论实践

本篇讲解机器学习理论。涵盖线性回归与逻辑回归的理论与实践,重点讲解数据预处理、模型构建与训练、性能评估及可视化,结合PaddlePaddle框架,系统学习深度学习开发流程并积累实战经验

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【paddlepaddle】基础理论教程 - 机器学习理论实践 - 创想鸟

前言

上一节我们从机器学习的基础出发,逐步实现了线性回归和分类任务。现在我们将通过加州房价预测的线性回归问题,理解了如何使用简单的线性模型进行数值预测。

接着,我们使用Logistic 回归解决了Moon100数据集的分类问题,并通过优化算法提升了模型的准确性。

逐步让大家熟练学习机器学习的理论和实践

一、利用Paddle实现基于线性回归的加州房价预测

1.1 数据集介绍

我们将使用 加州房价数据集(California Housing Dataset)作为本案例的研究对象。该数据集包含 1990年加州普查区 的房价与其他特征信息,用于研究地区特征与房价之间的关系。数据集共有 20640条样本 和 8个特征,目标变量是该地区的房价中位数。

1.1.1 数据集特征说明

以下是数据集中的特征描述:

特征名称 描述 单位

MedInc区域收入中位数万美元HouseAge区域房屋年龄中位数年AveRooms每户平均房间数无单位AveBedrms每户平均卧室数无单位Population区域人口数量人AveOccup每户平均入住人数人Latitude区域纬度度Longitude区域经度度Target(目标变量)房价中位数(待预测)万美元

1.1.2 目标分析

本案例的目标是通过 线性回归模型 预测区域的房价中位数(Target),并评估模型的性能。同时,尝试通过特征工程和正则化方法改进模型效果。

In [1]

# 导入必要库import paddlefrom sklearn.datasets import fetch_california_housingimport pandas as pd# 加载加州房价数据集housing = fetch_california_housing(as_frame=True)# 转换为DataFramedata = housing.frame# 显示数据集基本信息print("数据集基本信息:")print(data.info())# 显示前几行样本print("数据集示例:")print(data.head())# 查看目标变量分布print("目标变量分布(房价中位数):")print(data['MedHouseVal'].describe())
/opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages/paddle/utils/cpp_extension/extension_utils.py:686: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md  warnings.warn(warning_message)
数据集基本信息:RangeIndex: 20640 entries, 0 to 20639Data columns (total 9 columns): #   Column       Non-Null Count  Dtype  ---  ------       --------------  -----   0   MedInc       20640 non-null  float64 1   HouseAge     20640 non-null  float64 2   AveRooms     20640 non-null  float64 3   AveBedrms    20640 non-null  float64 4   Population   20640 non-null  float64 5   AveOccup     20640 non-null  float64 6   Latitude     20640 non-null  float64 7   Longitude    20640 non-null  float64 8   MedHouseVal  20640 non-null  float64dtypes: float64(9)memory usage: 1.4 MBNone数据集示例:   MedInc  HouseAge  AveRooms  AveBedrms  Population  AveOccup  Latitude    8.3252      41.0  6.984127   1.023810       322.0  2.555556     37.88   1  8.3014      21.0  6.238137   0.971880      2401.0  2.109842     37.86   2  7.2574      52.0  8.288136   1.073446       496.0  2.802260     37.85   3  5.6431      52.0  5.817352   1.073059       558.0  2.547945     37.85   4  3.8462      52.0  6.281853   1.081081       565.0  2.181467     37.85      Longitude  MedHouseVal  0    -122.23        4.526  1    -122.22        3.585  2    -122.24        3.521  3    -122.25        3.413  4    -122.25        3.422  目标变量分布(房价中位数):count    20640.000000mean         2.068558std          1.153956min          0.14999025%          1.19600050%          1.79700075%          2.647250max          5.000010Name: MedHouseVal, dtype: float64

1.2 数据清洗与可视化分析

在机器学习任务中,数据清洗是模型构建的基础环节,目的是处理缺失值、异常值等可能影响模型性能的问题,同时通过可视化分析数据的分布和特征之间的关系。


1.2.1 数据清洗

(1) 缺失值分析

缺失值可能会导致模型无法正常训练。我们需要检查数据集是否存在缺失值,并采取适当措施进行填补或移除。

In [2]

# 检查缺失值missing_values = data.isnull().sum()print("各列缺失值情况:n", missing_values)# 若存在缺失值,可以选择删除或填充# 删除缺失值样本cleaned_data = data.dropna()# 或者使用均值填充filled_data = data.fillna(data.mean())print("清洗后的数据集基本信息:")print(cleaned_data.info())
各列缺失值情况: MedInc         0HouseAge       0AveRooms       0AveBedrms      0Population     0AveOccup       0Latitude       0Longitude      0MedHouseVal    0dtype: int64清洗后的数据集基本信息:RangeIndex: 20640 entries, 0 to 20639Data columns (total 9 columns): #   Column       Non-Null Count  Dtype  ---  ------       --------------  -----   0   MedInc       20640 non-null  float64 1   HouseAge     20640 non-null  float64 2   AveRooms     20640 non-null  float64 3   AveBedrms    20640 non-null  float64 4   Population   20640 non-null  float64 5   AveOccup     20640 non-null  float64 6   Latitude     20640 non-null  float64 7   Longitude    20640 non-null  float64 8   MedHouseVal  20640 non-null  float64dtypes: float64(9)memory usage: 1.4 MBNone

(2) 异常值处理

异常值是指数据中明显偏离常规范围的值。我们通常通过统计方法或可视化工具(如箱线图)来检测异常值。

IQR方法:利用四分位数间距(IQR)检测异常值。

异常值范围:小于 (Q1−1.5×IQR)(Q1−1.5×IQR) 或大于 (Q3+1.5×IQR)(Q3+1.5×IQR) 的值被视为异常值。

In [3]

# 统计每列的上下四分位数和异常值范围for col in data.columns[:-1]:  # 遍历所有特征列    Q1 = data[col].quantile(0.25)    Q3 = data[col].quantile(0.75)    IQR = Q3 - Q1    lower_bound = Q1 - 1.5 * IQR    upper_bound = Q3 + 1.5 * IQR        # 过滤异常值    outliers = data[(data[col]  upper_bound)]    print(f"{col} 列异常值数量:{len(outliers)}")        # 去除异常值(可选)    data = data[(data[col] >= lower_bound) & (data[col] <= upper_bound)]
MedInc 列异常值数量:681HouseAge 列异常值数量:0AveRooms 列异常值数量:439AveBedrms 列异常值数量:1116Population 列异常值数量:1063AveOccup 列异常值数量:528Latitude 列异常值数量:0Longitude 列异常值数量:0

1.3 数据集特征的箱线图可视化

箱线图是一种直观的统计图表,用于展示数据分布及检测异常值。通过绘制箱线图,我们可以快速发现数据的分布情况和离群点

通过箱线图,我们可以观察: 1. 各特征值的分布范围及中心位置。 2. 是否存在显著的离群点。 3. 不同特征的量级差异。

In [4]

!pip install seaborn
Looking in indexes: https://mirror.baidu.com/pypi/simple/, https://mirrors.aliyun.com/pypi/simple/Collecting seaborn  Downloading https://mirrors.aliyun.com/pypi/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl (294 kB)     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 294.9/294.9 kB 7.5 MB/s eta 0:00:00a 0:00:01Requirement already satisfied: numpy!=1.24.0,>=1.20 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from seaborn) (1.26.4)Requirement already satisfied: pandas>=1.2 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from seaborn) (2.2.3)Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from seaborn) (3.9.2)Requirement already satisfied: contourpy>=1.0.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.3.0)Requirement already satisfied: cycler>=0.10 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (0.12.1)Requirement already satisfied: fonttools>=4.22.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (4.54.1)Requirement already satisfied: kiwisolver>=1.3.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.4.7)Requirement already satisfied: packaging>=20.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (24.1)Requirement already satisfied: pillow>=8 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (10.4.0)Requirement already satisfied: pyparsing>=2.3.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (3.2.0)Requirement already satisfied: python-dateutil>=2.7 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (2.9.0.post0)Requirement already satisfied: pytz>=2020.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from pandas>=1.2->seaborn) (2024.2)Requirement already satisfied: tzdata>=2022.7 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from pandas>=1.2->seaborn) (2024.2)Requirement already satisfied: six>=1.5 in /opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib!=3.6.1,>=3.4->seaborn) (1.16.0)Installing collected packages: seabornSuccessfully installed seaborn-0.13.2

In [5]

import matplotlib.pyplot as pltimport seaborn as sns# 设置画图风格sns.set(style="whitegrid")# 选择部分特征绘制箱线图selected_features = ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population']# 绘制箱线图plt.figure(figsize=(12, 6))sns.boxplot(data=data[selected_features])plt.title("Boxplot of dataset feature.", fontsize=16)plt.xticks(fontsize=12)plt.ylabel("value", fontsize=12)plt.xlabel("feature", fontsize=12)plt.show()

1.4 数据特征归一化

在机器学习任务中,特征归一化 是特征工程的重要步骤。其目的是将不同量纲的特征值映射到相同的尺度范围,从而提高模型的训练效率和性能,尤其是在梯度下降算法和距离相关的模型(如线性回归、逻辑回归和支持向量机)中。


1.4.1 为什么需要特征归一化?

现实数据中,不同特征的取值范围可能存在巨大差异。例如:

收入中位数(MedInc):范围可能为 [0, 15]。人口数量(Population):范围可能为 [500, 40,000]。经纬度(Latitude 和 Longitude):范围为 [30, 50] 和 [-125, -115]。

这种差异会导致以下问题:

梯度更新不均衡:梯度下降时,不同特征的梯度大小会不一致,可能导致模型难以收敛或收敛速度过慢。模型偏向问题:未归一化的特征可能对模型决策产生不均衡的影响,例如范围较大的特征可能主导模型输出。优化器敏感性:大多数优化算法(如SGD)对特征的尺度变化较为敏感。


1.4.2 常见的特征归一化方法

(1) 最小-最大归一化(Min-Max Scaling)

将特征值线性缩放到指定范围(通常为 [0, 1] 或 [-1, 1])。

公式:

[x′=x−min(x)max(x)−min(x)][x′=max(x)−min(x)x−min(x)]

优点:

保持数据分布形状不变。对特征值范围的约束性强。

适用场景:

特征范围已知,且分布无显著异常值。

(2) 标准化(Standardization)

将特征值转化为标准正态分布(均值为0,标准差为1)。

公式: [x′=x−μσ][x′=σx−μ] 其中,(μ)(μ) 为均值,(σ(σ) 为标准差。

优点:

适合处理有偏分布数据。对异常值较为鲁棒。

适用场景:

特征范围未知,且数据分布可能存在不同量级。

(3) 对数缩放(Log Scaling)

对数变换将特征值压缩到较小范围。

公式: [x′=log⁡(x+1)][x′=log(x+1)]

适用场景:

特征值存在长尾分布,且非负。

(4) 归一化的对比

方法 数据分布影响 是否受异常值影响 适用范围

Min-Max归一化不改变分布易受异常值影响特征范围已知标准化转换为标准分布鲁棒特征范围未知,分布不均对数缩放减少长尾效应易受负值影响存在长尾分布In [10]

# # 使用最大最小归一化import numpy as npfrom sklearn.model_selection import train_test_split# 提取特征与目标变量features = data.iloc[:, :-1].valuestarget = data.iloc[:, -1].values# # 最小-最大归一化实现# def min_max_scaling(features):#     min_vals = np.min(features, axis=0)#     max_vals = np.max(features, axis=0)#     return (features - min_vals) / (max_vals - min_vals)# # # 应用归一化# # normalized_features = min_max_scaling(features)# # 数据集划分# X_train, X_test, y_train, y_test = train_test_split(normalized_features, target, test_size=0.2, random_state=42)

In [11]

# 标准化from sklearn.preprocessing import StandardScaler# 标准化实现scaler = StandardScaler()standardized_features = scaler.fit_transform(features)# 数据集划分X_train, X_test, y_train, y_test = train_test_split(standardized_features, target, test_size=0.2, random_state=42)

In [12]

import paddleimport paddle.nn.functional as F# 将数据转换为Paddle张量X_train_tensor = paddle.to_tensor(X_train, dtype='float32')X_test_tensor = paddle.to_tensor(X_test, dtype='float32')# 使用Paddle实现标准化mean = paddle.mean(X_train_tensor, axis=0)std = paddle.std(X_train_tensor, axis=0)X_train_normalized = (X_train_tensor - mean) / stdX_test_normalized = (X_test_tensor - mean) / stdprint("标准化后的训练数据:", X_train_normalized.numpy()[:5])
标准化后的训练数据: [[-0.5087326   1.4234632   0.12109426  0.05857366 -0.6497711   0.15639436   1.0031793  -1.2958153 ] [ 1.0481998  -0.8750934   0.9622561   2.2335987  -0.49749768  0.10866082   0.655153   -1.1851951 ] [ 0.66350424 -0.8750934  -0.05120656  0.2758133  -0.42929187 -0.79060733   0.7539172  -1.1751386 ] [ 2.9235477   0.76673275  2.0087693  -0.01296391  0.00373571 -0.74548185  -0.72284335  0.6651809 ] [-1.147807    0.5204589  -0.953951    0.690019   -0.93687    -0.79818255  -0.4500659   0.75066024]]
W0108 10:22:09.703733   294 dygraph_functions.cc:83253] got different data type, run type promotion automatically, this may cause data type been changed.

(5)可视化归一化效果

In [13]

import matplotlib.pyplot as pltplt.figure(figsize=(12, 6))plt.boxplot(features, labels=data.columns[:-1])plt.title("Feature distribution before normalization") # 归一化前特征分布plt.xticks(rotation=45)plt.show()
/tmp/ipykernel_294/2547550394.py:4: MatplotlibDeprecationWarning: The 'labels' parameter of boxplot() has been renamed 'tick_labels' since Matplotlib 3.9; support for the old name will be dropped in 3.11.  plt.boxplot(features, labels=data.columns[:-1])

In [15]

plt.figure(figsize=(12, 6))plt.boxplot(standardized_features)plt.title("Feature distribution after normalization") # 归一化后特征分布(Min-Max)plt.show()

1.5 模型构建

在完成数据处理后,我们开始进入模型构建部分。本文将使用 PaddlePaddle 框架来自定义一个线性回归模型,并通过最小二乘法的解析解直接求解模型参数,从而避免复杂的迭代训练过程。


1.5.1 自定义 Linear 算子

PaddlePaddle 提供了灵活的算子设计接口,可以通过继承 paddle.nn.Layer 来定义自定义算子。我们首先构建一个简单的线性算子。

In [16]

import paddleimport paddle.nn as nnimport paddle.nn.functional as F# 自定义Linear算子class Linear(nn.Layer):    def __init__(self, in_features, out_features):        super(Linear, self).__init__()        # 初始化权重和偏置        self.weight = self.create_parameter(            shape=[in_features, out_features],            default_initializer=nn.initializer.XavierUniform())        self.bias = self.create_parameter(            shape=[out_features],            default_initializer=nn.initializer.Constant(0.0))    def forward(self, x):        # 线性变换公式:y = Wx + b        return paddle.matmul(x, self.weight) + self.bias

1.5.2 定义 Runner 类

Runner 类是模型训练的核心封装,我们将其用于配置模型、损失函数、优化器,以及完成模型的训练、评价和预测任务。

In [17]

# Runner类定义class Runner:    def __init__(self, input_dim, regularization_lambda=0.01):        """        初始化线性回归模型以及其他必需的参数        """        self.model = Linear(in_features=input_dim, out_features=1)        self.loss_fn = F.mse_loss  # 均方误差损失        self.optimizer = paddle.optimizer.SGD(parameters=self.model.parameters(), learning_rate=0.01)        self.regularization_lambda = regularization_lambda  # L2正则化项    def prepare_model(self, X_train, y_train):        """        使用正规方程(带L2正则化)来求解模型的权重和偏置        """        # 转换为Paddle张量        X_train_tensor = paddle.to_tensor(X_train, dtype='float32')        y_train_tensor = paddle.to_tensor(y_train, dtype='float32')        # 添加偏置项到 X_train        X_train_with_bias = paddle.concat([X_train_tensor, paddle.ones([X_train_tensor.shape[0], 1], dtype='float32')], axis=1)        # 正规方程解析解:W = (X^T X + λI)^-1 X^T y        X_transpose = paddle.transpose(X_train_with_bias, perm=[1, 0])                # 加上正则化项 (λI)        identity_matrix = paddle.eye(X_train_with_bias.shape[1])        regularization_matrix = self.regularization_lambda * identity_matrix                # 计算正规方程解        weights = paddle.matmul(            paddle.inverse(paddle.matmul(X_transpose, X_train_with_bias) + regularization_matrix),            paddle.matmul(X_transpose, y_train_tensor)        )        # 拆分权重和偏置        self.model.weight.set_value(weights[:-1].reshape([X_train.shape[1], 1]))  # 权重调整为二维张量        self.model.bias.set_value(weights[-1:].reshape([1]))  # 偏置调整为一维张量        print("解析解求得的模型参数:")        print("权重:", self.model.weight.numpy())        print("偏置:", self.model.bias.numpy())    def evaluate_model(self, X_test, y_test):        """        使用测试集进行模型评价        """        X_test_tensor = paddle.to_tensor(X_test, dtype='float32')        y_test_tensor = paddle.to_tensor(y_test, dtype='float32')        # 进行预测        predictions = self.model(X_test_tensor)        loss = self.loss_fn(predictions, y_test_tensor)        print("模型评价 - 测试集均方误差:", loss.numpy())        return predictions.numpy()    def predict(self, X_new):        """        对新数据进行预测        """        X_new_tensor = paddle.to_tensor(X_new, dtype='float32')        predictions = self.model(X_new_tensor)        return predictions.numpy()

1.5.3 使用 Runner 类来构建线性回归模型并完成训练、评价和预测。

In [18]

# 加载数据X_train, X_test, y_train, y_test = X_train_normalized, X_test_normalized, y_train, y_test# 创建 Runner 实例runner = Runner(input_dim=X_train.shape[1])# 使用最小二乘法解析解求解模型参数runner.prepare_model(X_train, y_train)# 评价模型predictions = runner.evaluate_model(X_test, y_test)# 对新数据进行预测X_new = X_test[:5]  # 假设我们使用测试集的前5条数据进行预测predicted_prices = runner.predict(X_new)print("预测结果(前5条):", predicted_prices)
解析解求得的模型参数:权重: [[ 0.7456653 ] [ 0.16260225] [-0.16771364] [ 0.1250522 ] [ 0.04790141] [-0.27607393] [-0.8478774 ] [-0.7796167 ]]偏置: [2.025095]模型评价 - 测试集均方误差: 1.9318573预测结果(前5条): [[1.5605581] [1.4985472] [1.6648219] [1.4926147] [1.280458 ]]

二、线性分类

在前边的学习过程中,通过对线性回归的学习,为我们提供了一种直观且基础的预测模型。通过将输入特征与目标变量之间的关系表示为一个线性方程,线性回归帮助我们理解了如何在多维空间中找到最优的拟合直线。然而,除了回归问题,分类问题也是机器学习中的重要领域。在许多应用场景中,我们需要根据输入数据的特征对样本进行分类。此时,线性分类模型成为了一种非常有效的选择。

与线性回归模型相似,线性分类模型通过线性方程来决定样本所属的类别。然而,线性分类的目标是将数据点分割成不同的类别,而不是预测一个连续的数值。接下来,我们将介绍线性分类的定义及其核心思想,并展示如何使用机器学习方法进行分类。

线性分类是一种基于线性模型的分类方法,旨在通过一个线性决策边界将样本分为不同的类别。其基本思想是利用线性函数来对数据进行分割,从而使得数据能够被映射到不同的类别标签。

具体来说,给定一个输入数据点 (x∈Rn)(x∈Rn),线性分类模型试图通过一个线性方程进行分类:

[y=sign(w1x1+w2x2+⋯+wnxn+b)][y=sign(w1x1+w2x2+⋯+wnxn+b)]

其中:

(w1,w2,…,wn)(w1,w2,…,wn) 是模型的权重,表示每个特征的重要性。(x1,x2,…,xn)(x1,x2,…,xn) 是输入特征。(b)(b) 是偏置项,用于调整决策边界的位置。(y)(y) 是模型的输出,它表示预测的类别,通常取值为 (±1)(±1) 或 0 和 1。

在训练过程中,线性分类器的目标是找到最佳的权重 (w)(w) 和偏置 (b)(b),使得决策边界能够最有效地将不同类别的样本分开。

与回归问题不同,线性分类模型的输出通常是一个类别标签,而不是一个连续的数值。根据训练数据的不同,线性分类器会调整其参数,使得分类边界最大程度地正确地划分样本。

常见的线性分类模型

常见的线性分类模型包括:

感知机(Perceptron):一种最简单的线性分类模型,基于梯度下降方法,通过不断调整权重来找到分割不同类别的超平面。支持向量机(SVM):通过最大化类别之间的间隔来寻找最优超平面,从而提高分类精度。逻辑回归(Logistic Regression):尽管名字中包含“回归”,它是一种广泛使用的线性分类模型,输出的是概率值,经过Sigmoid激活函数后用于二分类问题。Softmax回归: 解决了二分类问题中逻辑回归的局限,能够处理多个类别的分类问题。在Softmax回归中,我们通过一个线性模型计算每个类别的得分,然后通过Softmax函数将这些得分转换为概率,最终输出每个类别的预测概率

2.1 介绍 Logistic 回归

Logistic 回归(Logistic Regression)是一种广泛使用的统计模型,尽管其名称中带有“回归”二字,但它实际上是一种分类模型,主要用于解决二分类问题。Logistic 回归的核心思想是通过一个线性模型预测数据属于某一类别的概率。

2.1 Logistic 回归模型

在二分类问题中,我们通过线性模型计算一个实数值,然后使用Sigmoid函数(也称为Logistic函数)将其转换为一个0到1之间的概率值,表示数据属于某一类别的可能性。

假设输入特征为 (x∈Rn)(x∈Rn),模型的输出为类别 (y∈{0,1})(y∈{0,1}),则 Logistic 回归模型的预测概率为:

[P(y=1∣x)=σ(wTx+b)][P(y=1∣x)=σ(wTx+b)]

其中:

$( w $) 是特征的权重,$( x $) 是输入特征向量,$( b $) 是偏置项,$( sigma $) 是 Sigmoid 函数,它将线性函数的输出转换为概率。

2.2 相关的激活函数

Logistic 回归中使用的核心激活函数是 Sigmoid 函数,它的数学表达式为:

[σ(z)=11+e−z][σ(z)=1+e−z1]

Sigmoid 函数的作用是将输入值 ( z ) 映射到区间 ( (0, 1) ),这使得它非常适合用来表示概率。对于输入值 ( z ) 较大时,Sigmoid 输出接近 1,而当输入值较小时,输出接近 0。

Sigmoid 函数的特性

当 (z→+∞)(z→+∞),(σ(z)→1)(σ(z)→1)。当 (z→−∞)(z→−∞),(σ(z)→0)(σ(z)→0)。Sigmoid 函数是一个S型曲线,具有平滑的导数,适合用于梯度下降优化。

2.3. Logistic 函数实现代码

使用PaddlePaddle框架,实现一个简单的 Logistic 回归模型的实现代码

Logistic 函数实现了标准的 Sigmoid 激活函数 (σ(z)=11+e−z)(σ(z)=1+e−z1)

使用 paddle.linspace 生成从 -10 到 10 的等间距数值,并将这些值输入到 Logistic 函数中,计算其对应的输出值。

In [19]

import paddle# 定义 Logistic 函数def Logistic(x):    return 1 / (1 + paddle.exp(-x))# 创建一组从 -10 到 10 的数值x = paddle.linspace(-10, 10, 10000)# 计算 Logistic 函数值y = Logistic(x)# 打印结果的前几项print(y[:10])  # 输出前10项# 可视化 Logistic 函数import matplotlib.pyplot as pltplt.plot(x.tolist(), y.tolist(),color = 'red')plt.title('Sigmoid Function (Logistic)')plt.xlabel('z')plt.ylabel('σ(z)')plt.grid(True)plt.show()
Tensor(shape=[10], dtype=float32, place=Place(cpu), stop_gradient=True,       [0.00004540, 0.00004549, 0.00004558, 0.00004567, 0.00004576, 0.00004585,        0.00004595, 0.00004604, 0.00004613, 0.00004622])

函数解析

X轴:表示线性模型的输出 (z=wTx+b)(z=wTx+b)Y轴:表示通过 Sigmoid 激活函数得到的概率值 (σ(z))(σ(z))。当 ( z ) 较大时,Sigmoid 输出接近 1,表示类别1的概率很高。当 ( z ) 较小时,Sigmoid 输出接近 0,表示类别0的概率很高。在 ( z = 0 ) 时,Sigmoid 输出为 0.5,表示类别1和类别0的概率相等。

2.4 基于Logistic实现Moon1000数据集回归测试

我们将构建一个简单的二分类数据集,使用的是 Moon1000 数据集,这是一个由两个半月形状的数据集,常用于测试二分类模型的性能。

make_moons:我们生成了 1000 条带有噪声(noise=0.1)的二分类数据,形成了两个半月形状的数据集。

StandardScaler:对数据进行标准化处理,使其均值为 0,标准差为 1,这有助于提高模型训练的效果。

plt.scatter:通过不同的颜色和标记(Class 0 用蓝色,Class 1 用红色)绘制两类数据点。

In [20]

# 使用 `sklearn.datasets.make_moons` 来生成一个二分类的数据集。随机抽取其中的 1000 个样本,import numpy as npimport matplotlib.pyplot as pltfrom sklearn.datasets import make_moonsfrom sklearn.preprocessing import StandardScaler# 生成 Moon 数据集X, y = make_moons(n_samples=1000, noise=0.1, random_state=42)# 数据标准化scaler = StandardScaler()X_scaled = scaler.fit_transform(X)# 可视化数据分布plt.figure(figsize=(8, 6))plt.scatter(X_scaled[y == 0][:, 0], X_scaled[y == 0][:, 1], color='b', label='Class 0', s=10)plt.scatter(X_scaled[y == 1][:, 0], X_scaled[y == 1][:, 1], color='r', label='Class 1', s=10)plt.title('Moon1000 Dataset Visualization')plt.xlabel('Feature 1')plt.ylabel('Feature 2')plt.legend()plt.grid(True)plt.show()

In [21]

# 拆分数据集(训练集、验证集、测试集)from sklearn.model_selection import train_test_split# 第一次拆分:将数据集分为训练集(60%)和临时集(40%)X_train, X_temp, y_train, y_temp = train_test_split(X_scaled, y, test_size=0.4, random_state=42)# 第二次拆分:将临时集分为验证集(20%)和测试集(20%)X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)# 打印数据集形状print(f"训练集特征 X_train 形状: {X_train.shape}")print(f"验证集特征 X_val 形状: {X_val.shape}")print(f"测试集特征 X_test 形状: {X_test.shape}")print(f"训练集标签 y_train 形状: {y_train.shape}")print(f"验证集标签 y_val 形状: {y_val.shape}")print(f"测试集标签 y_test 形状: {y_test.shape}")
训练集特征 X_train 形状: (600, 2)验证集特征 X_val 形状: (200, 2)测试集特征 X_test 形状: (200, 2)训练集标签 y_train 形状: (600,)验证集标签 y_val 形状: (200,)测试集标签 y_test 形状: (200,)

2.5 构建 Logistic 回归模型

In [22]

import paddleimport paddle.nn as nnimport paddle.optimizer as optimimport paddle.nn.functional as F# 自定义 Logistic 回归模型(仅用 paddle.matmul)class LogisticRegression(nn.Layer):    def __init__(self, input_dim):        super(LogisticRegression, self).__init__()        # 定义线性层        self.params = {}        self.params['w'] = paddle.zeros([input_dim, 1])        self.params['b'] = paddle.zeros(shape = [1])        self.fc = nn.Linear(input_dim, 1)    def forward(self, x):        # 使用 paddle.matmul 计算加权和        logits = paddle.matmul(x, self.params['w']) + self.params['b']        outputs = Logistic(logits)        return outputs  # 这里没有使用激活函数 sigmoid

In [23]

paddle.seed(0)input = paddle.randn([3, 4])print(input)model = LogisticRegression(4)output = model(input)print(output)
Tensor(shape=[3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,       [[-0.75711036, -0.38059190,  0.10946669,  1.34467661],        [-0.84002435, -1.27341712,  2.47224617,  0.14070207],        [ 0.60608417,  0.23396523,  1.35604191,  0.10350471]])Tensor(shape=[3, 1], dtype=float32, place=Place(cpu), stop_gradient=True,       [[0.50000000],        [0.50000000],        [0.50000000]])

2.6 损失函数介绍

损失函数(Loss Function),也叫代价函数(Cost Function),在机器学习中是评估模型预测结果与真实结果之间差异的一个函数。损失函数的主要作用是通过量化模型的预测误差来引导优化过程,最终帮助模型调整参数,使得预测结果更加精确。

1. 损失函数的定义与作用

损失函数是一个数学函数,用来衡量模型的预测输出与真实标签之间的差异。其核心作用是:

量化预测误差用于优化算法的目标函数引导模型参数的调整

通常,损失函数的值越小,表示模型的预测结果与真实值的差距越小,因此,优化算法的目标就是通过不断最小化损失函数来训练模型。

2. 损失函数的公式

在不同的任务中,损失函数有所不同。常见的损失函数包括:

均方误差(Mean Squared Error,MSE):用于回归问题,公式如下:

L(y,y^)=1N∑i=1N(yi−y^i)2L(y,y^)=N1i=1∑N(yi−y^i)2

其中,yiyi 为真实值,y^iy^i 为预测值,NN 为样本数量。

交叉熵(Cross-Entropy):用于分类问题,特别是二分类和多分类任务,公式如下:

对于二分类,交叉熵损失函数可以写为:

L(y,y^)=−1N∑i=1N[yilog⁡(y^i)+(1−yi)log⁡(1−y^i)]L(y,y^)=−N1i=1∑N[yilog(y^i)+(1−yi)log(1−y^i)]

对于多分类,交叉熵损失函数可以写为:

L(y,y^)=−∑i=1Cyilog⁡(y^i)L(y,y^)=−i=1∑Cyilog(y^i)

其中,yiyi 是实际类别标签(通常是一个 one-hot 向量),y^iy^i 是预测的类别概率,CC 是类别数。

3. 交叉熵损失函数

交叉熵损失函数主要用于分类问题,尤其是在处理二分类和多分类任务时广泛应用。交叉熵的基本思想是量化两个概率分布之间的差异,通常用于衡量模型输出的概率分布与实际分布之间的差距。

二分类交叉熵:当标签是二分类时,交叉熵损失函数用于度量二进制分类模型输出的概率和真实标签之间的差异。

多分类交叉熵:对于多分类问题,交叉熵损失会计算所有类别的概率差异,并选择具有最大概率的类别作为模型的输出。

4. 构建交叉熵损失函数类代码

以下是一个简单的交叉熵损失函数实现,代码使用了 PaddlePaddle 框架:

In [24]

import paddleimport paddle.nn as nnclass CrossEntropyLoss(nn.Layer):    def __init__(self):        super(CrossEntropyLoss, self).__init__()    def forward(self, logits, labels):        """        计算交叉熵损失        :param logits: 预测值(通常是模型的输出,没有经过 softmax 的原始值)        :param labels: 真实标签,通常是 one-hot 编码        :return: 交叉熵损失        """        # 使用 PaddlePaddle 的函数计算交叉熵损失        loss = nn.functional.cross_entropy(logits, labels)        return loss# 示例:使用自定义交叉熵损失函数logits = paddle.to_tensor([[1.2, 0.3, -0.5], [0.7, 1.4, -1.0]], dtype='float32')  # 模拟模型输出labels = paddle.to_tensor([0, 1], dtype='int64')  # 假设有两个样本,标签分别为类别 0 和类别 1loss_fn = CrossEntropyLoss()loss = loss_fn(logits, labels)print("交叉熵损失:", loss.numpy())
交叉熵损失: 0.46265036

2.7 回归模型优化 – 梯度优化

梯度优化(Gradient Optimization)是机器学习中最常用的优化方法之一,它基于梯度下降算法(Gradient Descent)来通过调整模型的参数,最小化损失函数,从而提高模型的预测性能。在训练过程中,模型的参数通过计算梯度并朝着损失函数的最小值方向进行更新。

1. 梯度计算

梯度计算是优化算法的核心步骤,它用于计算损失函数相对于模型参数的偏导数。梯度描述了损失函数在某个点上的变化率,并指示了如何调整参数以减少损失。

损失函数:在逻辑回归中,常用的损失函数是交叉熵损失函数,计算的是模型预测与实际标签之间的差异。偏导数:偏导数是衡量一个参数对损失函数变化的敏感程度,即参数变化时,损失函数的变化量。计算每个参数的偏导数可以告诉我们如何调整该参数以减少损失。

2. 偏导数计算

对于逻辑回归的交叉熵损失函数,损失函数可以表示为:

L(y,y^)=−(ylog⁡(y^)+(1−y)log⁡(1−y^))L(y,y^)=−(ylog(y^)+(1−y)log(1−y^))

其中,y^=σ(Wx+b)y^=σ(Wx+b) 为模型的预测输出,yy 为实际标签,WW 为权重,bb 为偏置,σσ 为Sigmoid激活函数。

为了优化权重和偏置,我们需要计算损失函数相对于模型参数(权重 WW 和偏置 bb)的偏导数。通过链式法则,我们可以得到每个参数的梯度:

对权重 WW 的梯度:

∂L∂W=1N∑i=1N(y^i−yi)xi∂W∂L=N1i=1∑N(y^i−yi)xi

对偏置 bb 的梯度:

∂L∂b=1N∑i=1N(y^i−yi)∂b∂L=N1i=1∑N(y^i−yi)

3. Backward函数的实现

为了在逻辑回归模型中实现梯度计算,我们需要增加一个 backward 函数来计算损失函数的梯度。该函数将根据模型的输入数据和实际标签计算出每个参数的梯度,并将其存储在模型的 grads 属性中。

In [25]

import paddleimport paddle.nn as nn# 自定义 Logistic 回归模型(仅用 paddle.matmul)class LogisticRegression(nn.Layer):    def __init__(self, input_dim):        super(LogisticRegression, self).__init__()        # 定义线性层        self.params = {}        self.params['w'] = paddle.zeros([input_dim, 1])  # 初始化权重        self.params['b'] = paddle.zeros(shape=[1])  # 初始化偏置        self.fc = nn.Linear(input_dim, 1)    def forward(self, x):        # 使用 paddle.matmul 计算加权和        logits = paddle.matmul(x, self.params['w']) + self.params['b']        outputs = self.sigmoid(logits)        return outputs    def sigmoid(self, x):        # Sigmoid 激活函数        return 1 / (1 + paddle.exp(-x))    def backward(self, x, y):        """        计算损失函数对模型参数的梯度,并将其存放在 grads 属性中。        :param x: 输入特征        :param y: 真实标签        :return: None        """        # 计算预测输出        logits = paddle.matmul(x, self.params['w']) + self.params['b']        y_pred = self.sigmoid(logits)        # 计算损失函数对权重的偏导数        dw = paddle.matmul(paddle.transpose(x, [1, 0]), (y_pred - y)) / x.shape[0]        db = paddle.sum(y_pred - y) / x.shape[0]        # 将梯度存放在 grads 属性中        self.grads = {}        self.grads['w'] = dw        self.grads['b'] = db        # 输出计算的梯度        print("梯度 w:", dw.numpy())        print("梯度 b:", db.numpy())

In [26]

# 使用 backward 函数进行梯度计算# 模型创建与输入数据生成input_dim = 2model = LogisticRegression(input_dim)# 随机生成输入数据和标签x_sample = paddle.to_tensor([[0.5, 1.0], [1.5, -1.0], [1.0, 2.0]], dtype='float32')y_sample = paddle.to_tensor([[1], [0], [1]], dtype='float32')# 前向计算outputs = model(x_sample)print("模型输出:", outputs.numpy())# 计算梯度model.backward(x_sample, y_sample)# 查看存储的梯度print("存储在 grads 中的权重梯度:", model.grads['w'].numpy())print("存储在 grads 中的偏置梯度:", model.grads['b'].numpy())
模型输出: [[0.5] [0.5] [0.5]]梯度 w: [[ 0.       ] [-0.6666667]]梯度 b: -0.16666667存储在 grads 中的权重梯度: [[ 0.       ] [-0.6666667]]存储在 grads 中的偏置梯度: -0.16666667

2.8 模型优化 – 设计优化器

在模型训练过程中,优化器的作用是根据计算得到的梯度来调整模型的参数,逐步最小化损失函数,从而提高模型的预测能力。常见的优化算法有梯度下降(Gradient Descent)及其变种,如随机梯度下降(SGD)、Adam等。

1. 梯度下降法(Gradient Descent)

梯度下降法是最基本的优化算法,主要思想是通过计算损失函数的梯度,并按梯度的反方向更新参数,以便使损失函数逐步减小,直至收敛。

梯度下降的更新公式

对于一个模型的参数 θθ,在每一次迭代中,梯度下降法通过以下公式更新参数:

θ:=θ−η∂L∂θθ:=θ−η∂θ∂L

其中:

θθ 是模型的参数(例如,权重 WW 和偏置 bb)。ηη 是学习率(learning rate),控制着每次更新的步长。∂L∂θ∂θ∂L 是损失函数 LL 关于参数 θθ 的梯度。

计算梯度并进行更新

假设我们有一个模型 f(x,θ)f(x,θ),其损失函数为 L(y,f(x,θ))L(y,f(x,θ)),我们首先通过反向传播计算出模型的梯度。然后使用梯度下降算法,通过以下步骤更新参数:

计算损失函数 LL 对于模型参数 θθ 的梯度 ∂L∂θ∂θ∂L。

根据梯度更新模型参数:

θnew=θ−η⋅∂L∂θθnew=θ−η⋅∂θ∂L

在每次迭代中,参数会沿着梯度的反方向进行调整。

2. 优化器设计 – 自定义梯度下降

在设计优化器时,我们需要使用梯度下降法来更新模型参数。假设我们有一个简单的逻辑回归模型,已经通过 backward 函数计算了梯度,接下来,我们使用优化器来更新模型的权重和偏置。

In [27]

import paddleimport paddle.nn as nn# 自定义 Logistic 回归模型(仅用 paddle.matmul)class LogisticRegression(nn.Layer):    def __init__(self, input_dim):        super(LogisticRegression, self).__init__()        # 定义线性层        self.params = {}        self.params['w'] = paddle.zeros([input_dim, 1])  # 初始化权重        self.params['b'] = paddle.zeros(shape=[1])  # 初始化偏置        self.fc = nn.Linear(input_dim, 1)    def forward(self, x):        # 使用 paddle.matmul 计算加权和        logits = paddle.matmul(x, self.params['w']) + self.params['b']        outputs = self.sigmoid(logits)        return outputs    def sigmoid(self, x):        # Sigmoid 激活函数        return 1 / (1 + paddle.exp(-x))    def backward(self, x, y):        """        计算损失函数对模型参数的梯度,并将其存放在 grads 属性中。        :param x: 输入特征        :param y: 真实标签        :return: None        """        # 计算预测输出        logits = paddle.matmul(x, self.params['w']) + self.params['b']        y_pred = self.sigmoid(logits)        # 计算损失函数对权重的偏导数        dw = paddle.matmul(paddle.transpose(x, [1, 0]), (y_pred - y)) / x.shape[0]        db = paddle.sum(y_pred - y) / x.shape[0]        # 将梯度存放在 grads 属性中        self.grads = {}        self.grads['w'] = dw        self.grads['b'] = db        # 输出计算的梯度        # print("梯度 w:", dw.numpy())        # print("梯度 b:", db.numpy())    def update_params(self, lr=0.01):        """        使用梯度下降法更新模型的权重和偏置        :param lr: 学习率        :return: None        """        # 更新权重和偏置        self.params['w'] = self.params['w'] - lr * self.grads['w']        self.params['b'] = self.params['b'] - lr * self.grads['b']        # print("更新后的权重 w:", self.params['w'].numpy())        # print("更新后的偏置 b:", self.params['b'].numpy())

2.9 模型训练与优化

通过以下步骤进行模型训练,并应用自定义优化器来更新参数:

1.定义模型并初始化。

2.计算每个小批次的梯度。

3.使用梯度下降法更新模型参数。

4.重复以上步骤,直到损失函数收敛。

In [71]

# 将数据集转换为 Paddle 张量X_train_tensor = paddle.to_tensor(X_train, dtype='float32')y_train_tensor = paddle.to_tensor(y_train.reshape(-1, 1), dtype='float32')  # 确保标签形状匹配# 构建模型input_dim = X_train.shape[1]  # 输入特征的维度model = LogisticRegression(input_dim)# 训练过程epochs = 10000learning_rate = 0.01for epoch in range(epochs):    # 前向计算    outputs = model(X_train_tensor)        # 计算梯度    model.backward(X_train_tensor, y_train_tensor)        # 更新参数    model.update_params(lr=learning_rate)        # 每200回合打印一次损失值    if (epoch + 1) % 200 == 0:        # 计算预测值与实际标签的损失        logits = paddle.matmul(X_train_tensor, model.params['w']) + model.params['b']        predictions = model.sigmoid(logits)        loss = paddle.mean(-y_train_tensor * paddle.log(predictions) - (1 - y_train_tensor) * paddle.log(1 - predictions))        print(f"Epoch {epoch + 1}/{epochs}, Loss: {loss.numpy()}")
Epoch 200/10000, Loss: 0.434282124042511Epoch 400/10000, Loss: 0.35399749875068665Epoch 600/10000, Loss: 0.31881678104400635Epoch 800/10000, Loss: 0.2997851073741913Epoch 1000/10000, Loss: 0.2880668342113495Epoch 1200/10000, Loss: 0.2802077829837799Epoch 1400/10000, Loss: 0.2746124267578125Epoch 1600/10000, Loss: 0.2704521119594574Epoch 1800/10000, Loss: 0.26725637912750244Epoch 2000/10000, Loss: 0.2647395730018616Epoch 2200/10000, Loss: 0.26271817088127136Epoch 2400/10000, Loss: 0.2610691785812378Epoch 2600/10000, Loss: 0.25970688462257385Epoch 2800/10000, Loss: 0.25856953859329224Epoch 3000/10000, Loss: 0.25761178135871887Epoch 3200/10000, Loss: 0.25679925084114075Epoch 3400/10000, Loss: 0.25610560178756714Epoch 3600/10000, Loss: 0.2555100917816162Epoch 3800/10000, Loss: 0.25499647855758667Epoch 4000/10000, Loss: 0.25455155968666077Epoch 4200/10000, Loss: 0.2541647255420685Epoch 4400/10000, Loss: 0.2538272738456726Epoch 4600/10000, Loss: 0.25353190302848816Epoch 4800/10000, Loss: 0.2532727122306824Epoch 5000/10000, Loss: 0.2530447244644165Epoch 5200/10000, Loss: 0.25284361839294434Epoch 5400/10000, Loss: 0.2526659667491913Epoch 5600/10000, Loss: 0.25250861048698425Epoch 5800/10000, Loss: 0.2523690164089203Epoch 6000/10000, Loss: 0.2522450387477875Epoch 6200/10000, Loss: 0.25213468074798584Epoch 6400/10000, Loss: 0.25203630328178406Epoch 6600/10000, Loss: 0.2519485056400299Epoch 6800/10000, Loss: 0.2518700659275055Epoch 7000/10000, Loss: 0.25179991126060486Epoch 7200/10000, Loss: 0.25173699855804443Epoch 7400/10000, Loss: 0.2516807019710541Epoch 7600/10000, Loss: 0.25163009762763977Epoch 7800/10000, Loss: 0.25158464908599854Epoch 8000/10000, Loss: 0.2515437602996826Epoch 8200/10000, Loss: 0.2515070140361786Epoch 8400/10000, Loss: 0.25147390365600586Epoch 8600/10000, Loss: 0.25144410133361816Epoch 8800/10000, Loss: 0.2514171898365021Epoch 9000/10000, Loss: 0.2513929307460785Epoch 9200/10000, Loss: 0.25137099623680115Epoch 9400/10000, Loss: 0.2513512074947357Epoch 9600/10000, Loss: 0.2513332962989807Epoch 9800/10000, Loss: 0.2513171434402466Epoch 10000/10000, Loss: 0.25130248069763184

3.0 模型评估与预测

在训练完模型之后,我们需要对模型进行评估并在新的数据上进行预测。在这一部分,我们将介绍如何使用训练好的 Logistic 回归模型来进行评估和预测。

1. 模型评估

模型评估的核心是通过计算损失函数(如交叉熵损失)来度量模型在测试集上的表现。我们可以使用测试集的真实标签和模型预测结果计算损失,以了解模型在训练后是否有较好的泛化能力。

评估公式:

L(y,y^)=−1N∑i=1N[yilog⁡(y^i)+(1−yi)log⁡(1−y^i)]L(y,y^)=−N1i=1∑N[yilog(y^i)+(1−yi)log(1−y^i)]

其中,yy 为真实标签,y^y^ 为预测输出,NN 为样本数。

In [72]

# 模型评估def evaluate_model(model, X_test, y_test):    # 前向计算    logits = paddle.matmul(X_test, model.params['w']) + model.params['b']    predictions = model.sigmoid(logits)        # 计算交叉熵损失    loss = paddle.mean(-y_test * paddle.log(predictions) - (1 - y_test) * paddle.log(1 - predictions))    print(f"测试集损失: {loss.numpy()}")        # 预测标签    predicted_labels = (predictions > 0.5).astype('float32')  # 将 predicted_labels 转为 float32        # 计算准确率    accuracy = paddle.mean(paddle.cast(predicted_labels == y_test, dtype='float32'))        print(f"测试集准确率: {accuracy.numpy()}")    return predicted_labels.numpy()# 将数据转换为 Paddle 张量X_test_tensor = paddle.to_tensor(X_test, dtype='float32')y_test_tensor = paddle.to_tensor(y_test, dtype='float32')predicted_labels = evaluate_model(model, X_test_tensor, y_test_tensor)# print("预测标签:", predicted_labels)
测试集损失: 1.567063570022583测试集准确率: 0.5015000104904175

In [ ]


In [73]

# 将数据转换为 Paddle 张量X_test_tensor = paddle.to_tensor(X_test, dtype='float32')y_test_tensor = paddle.to_tensor(y_test, dtype='float32')# 测试阶段的预测predictions = model(X_test_tensor)  # 概率值predicted_labels = (predictions > 0.5).astype('int32')  # 转为二分类标签# # 检查预测结果分布# print("预测概率分布:", predictions.numpy().flatten())# print("预测标签分布:", predicted_labels.numpy().flatten())# 可视化对比plt.figure(figsize=(10, 6))# 实际标签可视化plt.subplot(1, 2, 1)plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test.flatten(), cmap='bwr', alpha=0.6)plt.title('Actual Labels')plt.xlabel('Feature 1')plt.ylabel('Feature 2')# 预测标签可视化plt.subplot(1, 2, 2)plt.scatter(X_test[:, 0], X_test[:, 1], c=predicted_labels.numpy().flatten(), cmap='bwr', alpha=0.6)plt.title('Predicted Labels')plt.xlabel('Feature 1')plt.ylabel('Feature 2')plt.tight_layout()plt.show()

以上就是【PaddlePaddle】基础理论教程 – 机器学习理论实践的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/72274.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
怎么收集办公用品需求量
上一篇 2025年11月13日 15:24:02
收集需求新闻稿怎么写的
下一篇 2025年11月13日 15:24:28

相关推荐

  • Discord用户头像链接的动态获取与管理:技术限制解析

    本文探讨了获取discord用户头像持久且自动更新链接的可能性。结论是,由于discord为每次上传的图片生成随机url,直接获取一个“永不失效”的静态链接是不可能的。若需在网页上展示动态更新的头像,开发者必须通过编程方式,利用discord api实时获取用户的最新头像url。 Discord头像…

    2026年5月10日
    000
  • CSS中背景图片与背景色的叠加及定位技巧

    本文深入探讨了在css中如何有效地将背景图片与背景颜色结合使用,并精确控制图片位置。文章首先介绍了background-image和background-color的基本层叠原理及定位属性,随后分析了背景图片不生效或定位异常的常见原因,特别是css优先级冲突。针对此问题,提供了使用!importan…

    2026年5月10日
    000
  • Golang的gRPC如何支持压缩传输 评估不同压缩算法对性能的影响

    Golang的gRPC如何支持压缩传输 评估不同压缩算法对性能的影响Golang的gRPC如何支持压缩传输 评估不同压缩算法对性能的影响Golang的gRPC如何支持压缩传输 评估不同压缩算法对性能的影响Golang的gRPC如何支持压缩传输 评估不同压缩算法对性能的影响

    在 golang 的 grpc 中启用压缩可通过设置 grpc 选项实现,具体步骤包括:1. 在客户端或服务端创建时指定默认压缩方式;2. 可在每次调用中单独控制压缩;3. 如需使用非默认算法需手动注册。可选算法有 gzip(压缩率高、cpu 消耗大)、snappy(速度快、压缩率低)、zstd(平…

    2026年5月10日 用户投稿
    100
  • Python网页版如何实现邮件发送_Python网页版邮件自动发送功能开发教程

    使用Flask和Flask-Mail可实现网页邮件发送功能,需配置SMTP服务(如QQ邮箱)、创建表单并处理发送逻辑,注意安全措施如环境变量管理密码、输入校验及异步发送优化。 在Python网页应用中实现邮件发送功能,是许多项目(如用户注册验证、密码重置、通知提醒等)的常见需求。本文将介绍如何使用F…

    2026年5月10日
    000
  • c++ socket编程入门 c++网络通信代码实例

    核心是使用socket API实现TCP通信,服务端依次创建套接字、绑定、监听、接受连接并收发数据,客户端则连接后发送消息并接收响应,需注意跨平台差异与错误处理。 想快速上手 C++ Socket 编程?其实核心就是使用操作系统提供的 socket API,通过创建套接字、绑定地址、监听连接(服务端…

    2026年5月10日
    000
  • 解决动态加载内容爬取问题:利用XHR请求获取隐藏数据

    本教程旨在解决使用beautifulsoup爬取网页时,因内容动态加载而无法获取目标数据的问题。当页面元素通过javascript的xhr请求异步加载时,直接解析初始html将失败。文章将详细阐述如何通过浏览器开发者工具识别这些xhr请求,并利用python的`requests`库直接调用api接口…

    2026年5月10日
    000
  • Python实现文本文件行号自动递增写入教程

    本教程详细介绍了如何使用python向文本文件追加数据时,自动为每行添加一个格式化的递增序列号。通过巧妙利用文件读写模式和文件指针定位,我们能够准确获取现有行数,并生成如”001″、”002″等格式的序列号,确保每次写入的数据都带有正确的行号。 Pyt…

    2026年5月10日
    000
  • 输出格式要求:项目文件夹重命名是否会破坏Python中的虚拟环境?

    项目文件夹重命名后,虚拟环境可能会失效。这是因为虚拟环境中的一些文件包含了硬编码的路径,指向原始的项目文件夹。重命名后,这些路径不再正确,导致虚拟环境无法正常激活和使用,从而影响项目依赖的管理和运行。 虚拟环境(venv)是Python中用于隔离项目依赖的常用工具。它通过创建一个独立的目录,并在其中…

    2026年5月10日
    000
  • 构建可直接链接的动态标签页:HTML、CSS与JavaScript实践指南

    本教程详细阐述了如何在Web页面中创建可直接链接到特定标签页内容的导航系统。通过结合HTML锚点、CSS样式和JavaScript动态逻辑,文章提供了一种优化方案,实现了按需加载、高效显示标签页内容,并确保了从外部URL直接访问特定标签页的功能。内容涵盖了从基础的JavaScript控制到更高级的动…

    2026年5月10日
    000
  • c++怎么将double转换为string_c++浮点数转字符串实现

    答案:C++中将double转为std::string常用方法包括std::to_string(简单但精度固定)、std::ostringstream(可控制精度)和std::to_chars(高性能,C++17+),推荐根据场景选择。 在C++中将double转换为std::string有多种方式…

    2026年5月10日
    000
  • 在树莓派上正确安装和配置Tesseract-OCR

    本文提供在树莓派上正确安装和配置Tesseract-OCR的详细教程。针对用户常遇到的因错误使用Windows二进制文件或Wine导致FileNotFoundError的问题,本教程将重点介绍如何利用Debian/Raspberry Pi OS原生软件包进行安装,并指导PyTesseract的正确路…

    2026年5月10日
    100
  • Python教程:从字符串中高效提取数值列表的最大值与最小值

    本教程将指导您如何在python中处理一个包含空格分隔数字的字符串,并从中高效地找出最大值和最小值。我们将探讨字符串拆分、类型转换、以及使用排序或内置函数来定位极端值的方法,最终将结果格式化为指定字符串输出。文章将提供详细的代码示例和注意事项,帮助您构建健壮的解决方案。 在日常编程中,我们经常会遇到…

    2026年5月10日
    300
  • C++文本文件读取与二进制文件读取区别

    文本模式自动转换换行符并适合纯文本处理,二进制模式原样读取数据确保完整性。1. 文本模式在Windows下将rn转为n,写入时反向转换;2. 二进制模式不作任何转换,保留原始字节;3. 文本文件可用>>或getline读取,二进制文件常用read()读取字节块;4. 跨平台场景需注意换行…

    2026年5月10日
    000
  • c++如何使用nullptr_c++空指针常量nullptr用法解析

    nullptr是C++11引入的类型安全空指针常量,其类型为std::nullptr_t,可隐式转换为任意指针类型但不转换为整型,解决了NULL和0在函数重载中因类型模糊导致的歧义问题,提升了代码的健壮性与可读性。 C++11引入的nullptr是专为表示空指针而设计的类型安全常量。它解决了C风格N…

    2026年5月10日
    000
  • python切片如何进行索引

    Python切片通过start:stop:step提取序列部分,遵循左闭右开原则,正向索引从0开始,反向从-1开始,省略参数取默认值,步长控制方向与间隔,不改变原序列且越界不报错。 Python切片通过指定起始、结束和步长来提取序列的一部分,使用方括号内的冒号分隔索引。基本语法是 sequence[…

    2026年5月10日
    000
  • 解决 Pyheif 安装失败:理解并安装 libheif 核心依赖

    Pyheif库在Python项目中用于处理HEIC/HEIF图像格式,但其安装常因缺少底层的C语言库libheif而失败。本文详细阐述了Pyheif与libheif的依赖关系,并提供了在macOS、Linux和Windows系统上安装libheif的具体步骤,从而解决Pyheif安装时常见的编译错误…

    2026年5月10日
    000
  • Golang反射安全吗 讨论Golang反射的安全性问题

    Golang反射安全吗 讨论Golang反射的安全性问题Golang反射安全吗 讨论Golang反射的安全性问题Golang反射安全吗 讨论Golang反射的安全性问题Golang反射安全吗 讨论Golang反射的安全性问题

    golang的反射机制在灵活性与安全性之间需要权衡,其安全性取决于使用方式。反射可能破坏类型安全,如通过reflect.valueof()和set()修改私有字段,导致类型错误和封装性破坏;同时带来性能开销,频繁调用反射方法会增加gc压力,影响高并发性能。为安全使用反射,应避免不必要的使用,优先考虑…

    2026年5月10日 用户投稿
    000
  • C++怎么处理资源泄漏 C++资源泄漏检测方法

    C++怎么处理资源泄漏 C++资源泄漏检测方法C++怎么处理资源泄漏 C++资源泄漏检测方法C++怎么处理资源泄漏 C++资源泄漏检测方法C++怎么处理资源泄漏 C++资源泄漏检测方法

    c++++处理资源泄漏的核心在于使用raii机制并结合工具与审查手段。1. raii通过对象生命周期管理资源,在构造时获取、析构时释放,确保异常安全;2. 智能指针如unique_ptr和shared_ptr自动管理内存,避免手动new/delete带来的泄漏;3. 静态分析工具如cppcheck、…

    2026年5月10日 用户投稿
    100
  • 如何使用Python实现基于图的异常检测?网络分析方法

    如何使用Python实现基于图的异常检测?网络分析方法如何使用Python实现基于图的异常检测?网络分析方法如何使用Python实现基于图的异常检测?网络分析方法如何使用Python实现基于图的异常检测?网络分析方法

    图异常检测的核心在于将数据抽象为图结构并识别异常节点、边或子图,具体步骤为:1. 数据转化为图,定义节点与边;2. 提取图特征如节点度、pagerank、聚类系数等;3. 根据业务场景定义异常行为,如节点度突变、社群结构异常等;4. 使用networkx等工具计算图指标,结合统计方法、社群检测、图嵌…

    2026年5月10日 用户投稿
    000
  • c++中如何使用pair返回多个值_c++ pair返回多个值技巧

    std::pair是C++中用于组合两个值的轻量模板类,常用于函数返回多个值。通过first和second成员访问元素,支持make_pair类型推导及C++17结构化绑定,适用于返回最小最大值等场景,但仅限双值,多值应使用tuple。 在C++中,pair 是一个非常实用的模板类,定义在 头文件中…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信