Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 之 [ 选择并训练模型 ] [ 模型微调 ] | 3/3(含分析过程)

news2024/9/20 20:44:40

Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 之 [ 选择并训练模型 ] [ 模型微调 ] | 3/3(含分析过程)

目录

Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 之 [ 选择并训练模型 ] [ 模型微调 ] | 3/3(含分析过程)

 一、简单介绍

二、机器学习

1、为什么使用机器学习?

2、机器学习系统的类型,及其对应的学习算法

3、机器学习可利用的开源数据

三、选择并训练模型

1、在训练集上训练和评估

2、使用交叉验证做更佳的评估

四、模型微调

1、网格搜索

2、随机搜索

3、集成方法

4、分析最佳模型和它们的误差

5、用测试集评估系统

五、启动、监控、维护系统

附录:

一、一些知识点

1、Scikit-Learn 设计

二、源码工程

三、该案例的环境 package 信息如下


 一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

Python 机器学习是利用 Python 编程语言中的各种工具和库来实现机器学习算法和技术的过程。Python 是一种功能强大且易于学习和使用的编程语言,因此成为了机器学习领域的首选语言之一。Python 提供了丰富的机器学习库,如Scikit-learn、TensorFlow、Keras、PyTorch等,这些库包含了许多常用的机器学习算法和深度学习框架,使得开发者能够快速实现、测试和部署各种机器学习模型。

通过 Python 进行机器学习,开发者可以利用其丰富的工具和库来处理数据、构建模型、评估模型性能,并将模型部署到实际应用中。Python 的易用性和庞大的社区支持使得机器学习在各个领域都得到了广泛的应用和发展。

二、机器学习

机器学习(Machine Learning)是人工智能(AI)的一个分支领域,其核心思想是通过计算机系统的学习和自动化推理,使计算机能够从数据中获取知识和经验,并利用这些知识和经验进行模式识别、预测和决策。机器学习算法能够自动地从数据中学习并改进自己的性能,而无需明确地编程。这一过程涉及对大量输入数据的分析和解释,以识别数据中的模式和趋势,并生成可以应用于新数据的预测模型。

1、为什么使用机器学习?

使用机器学习的原因主要包括以下几点:

  1. 高效性和准确性:机器学习算法能够处理大规模数据集,并从中提取有价值的信息,其预测和决策的准确性往往高于传统方法。
  2. 自动化和智能化:机器学习能够自动学习和改进,减少了对人工干预的依赖,提高了工作效率和智能化水平。
  3. 广泛应用性:机器学习在各个领域中都有广泛的应用,如图像识别、语音识别、自然语言处理、推荐系统、金融预测等,为许多实际问题的解决提供了有效的方法和工具。
  4. 未来趋势:随着人工智能技术的不断发展,机器学习已成为未来的趋势,掌握机器学习技能将有助于提高职业竞争力和创造力。

2、机器学习系统的类型,及其对应的学习算法

机器学习系统可以根据不同的学习方式和目标进行分类,主要包括以下几种类型及其对应的学习算法:

  1. 监督学习(Supervised Learning)

    • 定义:使用带有标签的训练数据来训练模型,以预测新数据的标签或目标值。
    • 常见算法
      • 线性回归(Linear Regression):用于预测连续值。
      • 逻辑回归(Logistic Regression):用于分类问题,尤其是二分类问题。
      • 支持向量机(SVM, Support Vector Machines):用于分类和回归问题,通过寻找最优的超平面来分割数据。
      • 决策树(Decision Trees)随机森林(Random Forests):通过构建决策树或决策树集合来进行分类或回归。
      • 神经网络(Neural Networks):模仿人脑神经元的工作方式,通过多层节点之间的连接和权重调整来进行学习和预测。
  2. 无监督学习(Unsupervised Learning)

    • 定义:在没有标签的情况下,从数据中发现隐藏的结构和模式。
    • 常见算法
      • 聚类算法(Clustering Algorithms):如K均值(K-Means)、层次聚类分析(HCA)等,用于将数据分组为具有相似特征的簇。
      • 降维算法(Dimensionality Reduction Algorithms):如主成分分析(PCA)、t-分布邻域嵌入算法(t-SNE)等,用于减少数据的维度以便于分析和可视化。
      • 异常检测(Anomaly Detection):用于识别数据中的异常点或离群点。
  3. 强化学习(Reinforcement Learning)

    • 定义:通过与环境的交互学习,以最大化累积奖励为目标。
    • 特点:强化学习不需要明确的标签或监督信号,而是根据环境给出的奖励或惩罚来指导学习过程。
    • 应用场景:游戏AI、机器人控制、自动驾驶等领域。
  4. 半监督学习(Semi-Supervised Learning)

    • 定义:处理部分带标签的训练数据,通常是大量不带标签数据加上小部分带标签数据。
    • 特点:结合了监督学习和无监督学习的特点,旨在利用未标记数据来提高模型的泛化能力。
    • 常见算法:多数半监督学习算法是非监督和监督算法的结合,如自训练(Self-Training)、协同训练(Co-Training)等。

3、机器学习可利用的开源数据

开源数据集可以根据需要进行选择,涵盖多个领域。以下是一些可以查找的数据的地方,供参考:

  • 流行的开源数据仓库:
    • UC Irvine Machine Learning Repository
    • Kaggle datasets
    • Amazon's AWS datasets
  • 准入口(提供开源数据列表)
    • - Data Portals
    • http://opendatamonitor.eu/
    • Financial, Economic and Alternative Data | Nasdaq Data Link
  • 其它列出流行开源数据仓库的网页:
    • Wikipedia's list of Machine Learning datasets
    • Quora.com question
    • Datasets subreddit

(注意:代码执行的时候,可能需要科学上网)

三、选择并训练模型

可到这一步了!你在前面限定了问题、获得了数据、探索了数据、采样了一个测试集、写了自动化的转换流水线来清理和为算法准备数据。现在,你已经准备好选择并训练一个机器学习模型了。

1、在训练集上训练和评估

好消息是基于前面的工作,接下来要做的比你想的要简单许多。我们先来训练一个线性回归模型:

from sklearn.linear_model import LinearRegression

# 创建LinearRegression模型的实例。
# LinearRegression是Scikit-Learn库中用于线性回归的类,它是一种监督学习算法,
# 用于预测连续的目标值,例如房价。这种算法试图找到特征和目标值之间的线性关系。
lin_reg = LinearRegression()

# 使用fit方法训练线性回归模型。
# 这个方法接受两个参数:特征矩阵housing_prepared和目标数组housing_labels。
# 特征矩阵是经过预处理的数据,目标数组是我们希望模型学习预测的中位数房价值。
# fit方法将根据提供的数据拟合线性回归模型的参数。
# 在模型训练完成后,lin_reg实例将包含用于预测的系数和截距。
lin_reg.fit(housing_prepared, housing_labels)

运行结果:

完毕!你现在就有了一个可用的线性回归模型。用一些训练集中的实例做下验证:

# 从housing DataFrame中选取前5行数据,存储在变量some_data中。
# 这些数据将用于模型的预测,以检查模型对已知数据的预测能力。
some_data = housing.iloc[:5]

# 从住房标签数组housing_labels中选取前5个标签,存储在变量some_labels中。
# 这些标签是模型预测的目标值,通常在实际应用中,我们不会使用这些标签来评估模型,
# 因为我们想要模型能够从未见过的数据中学习并做出准确的预测。
some_labels = housing_labels.iloc[:5]

# 使用之前定义的full_pipeline处理选取的数据some_data。
# transform方法将应用Pipeline中定义的所有转换步骤,包括特征选择、缺失值填充、
# 特征构造和标准化(对于数值型特征)以及独热编码(对于分类型特征)。
some_data_prepared = full_pipeline.transform(some_data)

# 使用训练好的线性回归模型lin_reg对处理后的数据some_data_prepared进行预测。
# predict方法将应用模型的参数来预测给定特征对应的目标值。
# 打印出模型的预测结果。
print("Predictions:", lin_reg.predict(some_data_prepared))

运行结果:

Predictions: [ 85657.90192014 305492.60737488 152056.46122456 186095.70946094
 244550.67966089]
# 从housing_labels中选取前5个标签,这些标签对应于some_data中的房屋的中位数房价。
# 由于some_labels是一个pandas Series,我们使用iloc[:5]来获取前5个元素。

# 将some_labels转换为列表并打印,这样我们可以查看实际的房价标签。
# 这为我们提供了一个直观的方式来比较模型的预测结果和实际的房价。
# 打印标签列表,以便于和上一步中的模型预测结果进行对比分析。
print("Labels:", list(some_labels))

运行结果:

Labels: [72100.0, 279600.0, 82700.0, 112500.0, 238300.0]

行的通,尽管预测并不怎么准确(比如,第三个预测偏离了 50%!)。让我们使用 Scikit-Learn 的mean_squared_error函数,用全部训练集来计算下这个回归模型的 RMSE:

from sklearn.metrics import mean_squared_error
import numpy as np

# 使用LinearRegression模型的predict方法对整个处理后的数据集housing_prepared进行预测。
# 这将返回一个数组,其中包含了对应于housing_labels中每个标签的预测值。
housing_predictions = lin_reg.predict(housing_prepared)

# 计算预测值和实际标签之间的均方误差(Mean Squared Error, MSE)。
# MSE是回归模型常用的性能评估指标,它衡量了预测值与实际值之间差异的平方的平均值。
# 通过计算MSE,我们可以了解模型预测的平均误差水平。
lin_mse = mean_squared_error(housing_labels, housing_predictions)

# 计算均方误差的平方根,得到均方根误差(Root Mean Squared Error, RMSE)。
# RMSE是MSE的标准化形式,它以相同的单位表示,与原始数据的单位相同,这使得它更易于解释。
lin_rmse = np.sqrt(lin_mse)

# 打印RMSE值,它提供了一个衡量模型预测精度的指标。
# 较小的RMSE值表示模型的预测更接近实际值,模型的性能更好。
print(lin_rmse)

运行结果:

68627.87390018745

OK,有总比没有强,但显然结果并不好:大多数街区的median_housing_values位于 120000 到 265000 美元之间,因此预测误差 68627 美元不能让人满意。这是一个模型欠拟合训练数据的例子。当这种情况发生时,意味着特征没有提供足够多的信息来做出一个好的预测,或者模型并不强大。修复欠拟合的主要方法是选择一个更强大的模型,给训练算法提供更好的特征,或去掉模型上的限制。这个模型还没有正则化,所以排除了最后一个选项。你可以尝试添加更多特征(比如,人口的对数值),但是首先让我们尝试一个更为复杂的模型,看看效果。

来训练一个DecisionTreeRegressor。这是一个强大的模型,可以发现数据中复杂的非线性关系。代码看起来很熟悉:

from sklearn.tree import DecisionTreeRegressor

# 创建DecisionTreeRegressor模型的实例。
# DecisionTreeRegressor是一个用于回归任务的决策树模型,它可以用于预测连续的数值变量,
# 例如房价。决策树通过学习简单的决策规则从数据特征中推断出目标值。

# random_state参数用于确保模型的可重复性。设置为固定的整数值(在这里是42),
# 使得每次模型训练时,随机数生成器的初始状态都是相同的,从而得到相同的结果。
tree_reg = DecisionTreeRegressor(random_state=42)

# 使用fit方法训练决策树回归模型。
# 这个方法接受两个参数:特征矩阵housing_prepared和目标数组housing_labels。
# 特征矩阵是经过预处理的数据,目标数组是我们希望模型学习预测的中位数房价。
# fit方法将根据提供的数据拟合决策树模型的参数。
# 在模型训练完成后,tree_reg实例将包含用于进行预测的决策树结构。
tree_reg.fit(housing_prepared, housing_labels)

运行结果:

现在模型就训练好了,用训练集评估下:

# 使用训练好的决策树回归模型tree_reg对整个处理后的数据集housing_prepared进行预测。
# predict方法将应用模型的决策树结构来预测给定特征对应的目标值。
# 将预测结果存储在变量housing_predictions中。
housing_predictions = tree_reg.predict(housing_prepared)

# 使用sklearn.metrics模块中的mean_squared_error函数计算决策树模型预测结果的均方误差(MSE)。
# 这是评估回归模型性能的一个常用指标,它衡量了模型预测值与实际值之间差异的平方的平均值。
# 均方误差越小,表示模型的预测值与实际值越接近。
tree_mse = mean_squared_error(housing_labels, housing_predictions)

# 计算均方误差的平方根,得到均方根误差(RMSE)。
# RMSE提供了预测误差的度量,与原始数据具有相同的单位,更易于直观理解。
# 它表示预测值与实际值偏差的平均大小。
tree_rmse = np.sqrt(tree_mse)

# 打印决策树模型的RMSE值,这是衡量模型预测精度的一个重要指标。
# 通过比较不同模型的RMSE值,我们可以评估哪个模型的预测性能更好。
print(tree_rmse)

运行结果:

0.0

等一下,发生了什么?没有误差?这个模型可能是绝对完美的吗?当然,更大可能性是这个模型严重过拟合数据。如何确定呢?如前所述,直到你准备运行一个具备足够信心的模型,都不要碰测试集,因此你需要使用训练集的部分数据来做训练,用一部分来做模型验证。

2、使用交叉验证做更佳的评估

评估决策树模型的一种方法是用函数train_test_split来分割训练集,得到一个更小的训练集和一个验证集,然后用更小的训练集来训练模型,用验证集来评估。这需要一定工作量,并不难而且也可行。

另一种更好的方法是使用 Scikit-Learn 的交叉验证功能。下面的代码采用了 K 折交叉验证(K-fold cross-validation):它随机地将训练集分成十个不同的子集,成为“折”,然后训练评估决策树模型 10 次,每次选一个不用的折来做评估,用其它 9 个来做训练。结果是一个包含 10 个评分的数组:

from sklearn.model_selection import cross_val_score
import numpy as np

# 使用cross_val_score函数进行交叉验证,这是一种评估模型性能的方法。
# 交叉验证有助于减少模型评估过程中的方差,并给出更可靠的性能估计。

# tree_reg是之前训练好的决策树回归模型。
# housing_prepared是经过预处理的特征数据集。
# housing_labels是对应的目标值数组。

# scoring参数设置为"neg_mean_squared_error",表示我们使用负均方误差作为评分标准。
# 在Scikit-Learn中,评分函数通常返回越大越好的值,因此最小化误差的评分(如MSE)是其负值。

# cv参数设置为10,表示将数据集分成10份进行10折交叉验证。

# 执行交叉验证,并返回一个数组scores,其中包含每次折的评分。
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
                         scoring="neg_mean_squared_error", cv=10)

# 计算交叉验证得到的MSE分数的平方根,得到RMSE分数。
# 由于cross_val_score返回的是负MSE,我们先取负值,然后求平方根,得到RMSE。
# 将得到的RMSE分数存储在变量tree_rmse_scores中。
tree_rmse_scores = np.sqrt(-scores)

注意:Scikit-Learn 交叉验证功能期望的是效用函数(越大越好)而不是损失函数(越低越好),因此得分函数实际上与 MSE 相反(即负值),这就是为什么前面的代码在计算平方根之前先计算-scores

来看下结果:

import numpy as np

# 定义一个函数display_scores,用于打印和显示一组分数的摘要统计信息。
# 这个函数接受一个参数scores,它是一个包含数值的数组或列表。
def display_scores(scores):
    # 打印原始分数。
    print("Scores:", scores)
    # 使用numpy的mean函数计算分数的平均值,并打印出来。
    print("Mean:", scores.mean())
    # 使用numpy的std函数计算分数的标准差,并打印出来。
    # 标准差是衡量数据分布离散程度的一个指标。
    print("Standard deviation:", scores.std())

# 调用display_scores函数,传入tree_rmse_scores。
# 这个函数将打印RMSE分数列表、它们的平均值和标准差。
# 这有助于快速了解交叉验证结果的分布情况,评估模型的稳定性和可靠性。
display_scores(tree_rmse_scores)

运行结果:

Scores: [72831.45749112 69973.18438322 69528.56551415 72517.78229792
 69145.50006909 79094.74123727 68960.045444   73344.50225684
 69826.02473916 71077.09753998]
Mean: 71629.89009727491
Standard deviation: 2914.035468468928

现在决策树就不像前面看起来那么好了。实际上,它看起来比线性回归模型还糟!注意到交叉验证不仅可以让你得到模型性能的评估,还能测量评估的准确性(即,它的标准差)。决策树的评分大约是 71600,通常波动有±2900。如果只有一个验证集,就得不到这些信息。但是交叉验证的代价是训练了模型多次,不可能总是这样。

让我们计算下线性回归模型的的相同分数,以做确保:

# 执行交叉验证,并返回一个数组lin_scores ,其中包含每次折的评分。
lin_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
                                scoring="neg_mean_squared_error", cv=10)

# 计算交叉验证得到的MSE分数的平方根,得到RMSE分数。
# 由于cross_val_score返回的是负MSE,我们先取负值,然后求平方根,得到RMSE。
# 将得到的RMSE分数存储在变量lin_rmse_scores 中。
lin_rmse_scores = np.sqrt(-lin_scores )

# 调用display_scores函数,传入lin_rmse_scores 。
# 这个函数将打印RMSE分数列表、它们的平均值和标准差。
# 这有助于快速了解交叉验证结果的分布情况,评估模型的稳定性和可靠性。
display_scores(lin_rmse_scores )

运行结果:

Scores: [66782.73843989 66960.118071   70347.95244419 74739.57052552
 68031.13388938 71193.84183426 64969.63056405 68281.61137997
 71552.91566558 67665.10082067]
Mean: 69052.46136345083
Standard deviation: 2731.674001798348

判断没错:决策树模型过拟合很严重,它的性能比线性回归模型还差。

现在再尝试最后一个模型:RandomForestRegressor。随机森林是通过用特征的随机子集训练许多决策树。在其它多个模型之上建立模型称为集成学习(Ensemble Learning),它是推进 ML 算法的一种好方法。我们会跳过大部分的代码,因为代码本质上和其它模型一样:

from sklearn.ensemble import RandomForestRegressor

# 创建RandomForestRegressor模型的实例。
# RandomForestRegressor是一个集成学习模型,它使用多个决策树来构建一个随机森林,
# 用于回归任务,可以用于预测连续的数值变量,例如房价。
# 这个模型通常比单一决策树更稳健,因为它减少了过拟合的风险。

# n_estimators参数设置为10,表示随机森林中将使用10棵树。增加树的数量可以提高模型的准确性,
# 但也会增加计算成本和过拟合的风险。
# random_state参数设置为42,用于确保模型训练的可重复性。设置为固定的整数值,
# 使得每次模型训练时,随机数生成器的初始状态都是相同的,从而得到相同的结果。
forest_reg = RandomForestRegressor(n_estimators=10, random_state=42)

# 使用fit方法训练随机森林回归模型。
# 这个方法接受两个参数:特征矩阵housing_prepared和目标数组housing_labels。
# 特征矩阵是经过预处理的数据,目标数组是我们希望模型学习预测的中位数房价。
# fit方法将根据提供的数据拟合随机森林模型的参数。
# 在模型训练完成后,forest_reg实例将包含用于进行预测的多棵决策树。
forest_reg.fit(housing_prepared, housing_labels)

运行结果:

# 使用训练好的随机森林回归模型forest_reg对整个处理后的数据集housing_prepared进行预测。
# predict方法将应用模型的随机森林结构来预测给定特征对应的目标值。
# 将预测结果存储在变量housing_predictions中。
housing_predictions = forest_reg.predict(housing_prepared)

# 使用sklearn.metrics模块中的mean_squared_error函数计算随机森林模型预测结果的均方误差(MSE)。
# MSE是回归模型常用的性能评估指标,它衡量了预测值与实际值之间差异的平方的平均值。
# 均方误差越小,表示模型的预测值与实际值越接近。
forest_mse = mean_squared_error(housing_labels, housing_predictions)

# 计算均方误差的平方根,得到均方根误差(RMSE)。
# RMSE是MSE的标准化形式,它以相同的单位表示,与原始数据的单位相同,这使得它更易于解释。
# 它表示预测值与实际值偏差的平均大小。
forest_rmse = np.sqrt(forest_mse)

# 打印随机森林模型的RMSE值,这是衡量模型预测精度的一个重要指标。
# 通过比较不同模型的RMSE值,我们可以评估哪个模型的预测性能更好。
print(forest_rmse)

运行结果:

22413.454658589766
# 执行交叉验证,并返回一个数组forest_scores,其中包含每次折的评分。
forest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
                                scoring="neg_mean_squared_error", cv=10)

# 计算交叉验证得到的MSE分数的平方根,得到RMSE分数。
# 由于cross_val_score返回的是负MSE,我们先取负值,然后求平方根,得到RMSE。
# 将得到的RMSE分数存储在变量forest_rmse_scores中。
forest_rmse_scores = np.sqrt(-forest_scores)

# 调用display_scores函数,传入forest_rmse_scores。
# 这个函数将打印RMSE分数列表、它们的平均值和标准差。
# 这有助于快速了解交叉验证结果的分布情况,评估模型的稳定性和可靠性。
display_scores(forest_rmse_scores)

运行结果:

Scores: [53519.05518628 50467.33817051 48924.16513902 53771.72056856
 50810.90996358 54876.09682033 56012.79985518 52256.88927227
 51527.73185039 55762.56008531]
Mean: 52792.92669114079
Standard deviation: 2262.8151900582

现在好多了:随机森林看起来很有希望。但是,训练集的评分仍然比验证集的评分低很多。解决过拟合可以通过简化模型,给模型加限制(即,规整化),或用更多的训练数据。在深入随机森林之前,你应该尝试下机器学习算法的其它类型模型(不同核心的支持向量机,神经网络,等等),不要在调节超参数上花费太多时间。目标是列出一个可能模型的列表(两到五个)。

提示:你要保存每个试验过的模型,以便后续可以再用。要确保有超参数和训练参数,以及交叉验证评分,和实际的预测值。这可以让你比较不同类型模型的评分,还可以比较误差种类。你可以用 Python 的模块pickle,非常方便地保存 Scikit-Learn 模型,或使用sklearn.externals.joblib,后者序列化大 NumPy 数组更有效率:

from sklearn.externals import joblib

joblib.dump(my_model, "my_model.pkl")
# 然后
my_model_loaded = joblib.load("my_model.pkl")

四、模型微调

假设你现在有了一个列表,列表里有几个有希望的模型。你现在需要对它们进行微调。让我们来看几种微调的方法。

1、网格搜索

微调的一种方法是手工调整超参数,直到找到一个好的超参数组合。这么做的话会非常冗长,你也可能没有时间探索多种组合。

你应该使用 Scikit-Learn 的GridSearchCV来做这项搜索工作。你所需要做的是告诉GridSearchCV要试验有哪些超参数,要试验什么值,GridSearchCV就能用交叉验证试验所有可能超参数值的组合。例如,下面的代码搜索了RandomForestRegressor超参数值的最佳组合:

from sklearn.model_selection import GridSearchCV

# 定义一个参数网格param_grid,它包含了一系列用于RandomForestRegressor的超参数组合。
# 这里尝试了不同的n_estimators(树的数量)和max_features(寻找最佳分裂时考虑的特征数量)。
# 第一个字典尝试了3、10、30个估计器和2、4、6、8个最大特征的组合。
# 第二个字典将bootstrap设置为False,并尝试了3、10个估计器和2、3、4个最大特征的组合。
param_grid = [
    # try 12 (3×4) combinations of hyperparameters
    {'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
    # then try 6 (2×3) combinations with bootstrap set as False
    {'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
]

# 创建RandomForestRegressor模型的实例,设置random_state参数以确保结果的可重复性。
forest_reg = RandomForestRegressor(random_state=42)

# 初始化GridSearchCV,它将通过交叉验证来寻找最佳的超参数组合。
# forest_reg是待优化的模型。
# param_grid是待搜索的参数网格。
# cv=5表示使用5折交叉验证。
# scoring='neg_mean_squared_error'表示使用负均方误差作为评分标准,以最小化误差。
# return_train_score=True表示返回训练分数,这有助于评估模型在训练集上的表现。
grid_search = GridSearchCV(forest_reg, param_grid, cv=5,
                           scoring='neg_mean_squared_error', return_train_score=True)

# 调用fit方法在housing_prepared特征数据集和housing_labels目标值上训练模型。
# 这将执行多次训练和验证,以找到最佳的超参数组合。
grid_search.fit(housing_prepared, housing_labels)

运行结果:

当你不能确定超参数该有什么值,一个简单的方法是尝试连续的 10 的幂(如果想要一个粒度更小的搜寻,可以用更小的数,就像在这个例子中对超参数n_estimators做的)。

param_grid告诉 Scikit-Learn 首先评估所有的列在第一个dict中的n_estimatorsmax_features3 × 4 = 12种组合(不用担心这些超参数的含义,会在第 7 章中解释)。然后尝试第二个dict中超参数的2 × 3 = 6种组合,这次会将超参数bootstrap设为False而不是True(后者是该超参数的默认值)。

总之,网格搜索会探索12 + 6 = 18RandomForestRegressor的超参数组合,会训练每个模型五次(因为用的是五折交叉验证)。换句话说,训练总共有18 × 5 = 90轮!K 折将要花费大量时间,完成后,你就能获得参数的最佳组合,如下所示:

# 在GridSearchCV完成fit方法后,best_params_属性将包含最佳超参数组合。
# 这个属性是一个字典,它记录了在交叉验证过程中表现最佳的超参数设置。
# 这些参数提供了模型的最佳性能,根据设定的评分标准(在这里是负均方误差)。

# 打印best_params_属性,查看GridSearchCV找到的最佳超参数。
# 这有助于我们了解哪些超参数的组合使得模型在交叉验证中表现最佳。
print(grid_search.best_params_)

运行结果:

{'max_features': 8, 'n_estimators': 30}

提示:因为 30 是n_estimators的最大值,你也应该估计更高的值,因为评估的分数可能会随n_estimators的增大而持续提升。

你还能直接得到最佳的估计器:

# 在GridSearchCV完成fit方法后,best_estimator_属性将包含使用最佳超参数组合训练出的模型实例。
# 这个属性提供了一个完全训练好的模型,它可以直接用于进行预测或进一步的评估。

# best_estimator_是基于best_params_属性中的超参数训练得到的,即在交叉验证中表现最佳的模型。

# 打印best_estimator_属性,查看GridSearchCV找到的最佳模型实例。
# 这有助于我们了解最终选择使用的模型配置,以及用于后续预测的模型状态。
grid_search.best_estimator_

运行结果:

注意:如果GridSearchCV是以(默认值)refit=True开始运行的,则一旦用交叉验证找到了最佳的估计器,就会在整个训练集上重新训练。这是一个好方法,因为用更多数据训练会提高性能。

当然,也可以得到评估得分:

# 在GridSearchCV完成fit方法后,cv_results_属性将包含交叉验证过程中的详细结果。
# 这个属性是一个字典,它记录了每次交叉验证的分数和对应的参数。

# cvres变量用于存储cv_results_属性的内容,以便我们可以迭代和分析结果。
cvres = grid_search.cv_results_

# 使用zip函数同时迭代cv_results_中的"mean_test_score"和"params"。
# "mean_test_score"是每次交叉验证在测试集上的平均分数(负均方误差)。
# "params"是参与交叉验证的参数设置。
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
    # 计算每次交叉验证的均方根误差(RMSE),方法是取负均方误差的平方根。
    # 由于存储的分数是负均方误差,我们先取其负值,然后求平方根。
    rms = np.sqrt(-mean_score)
    
    # 打印每次交叉验证的RMSE和对应的参数设置。
    # 这有助于我们了解不同参数设置下模型的性能,并找出最佳组合。
    print(rms, params)

运行结果:

63895.161577951665 {'max_features': 2, 'n_estimators': 3}
54916.32386349543 {'max_features': 2, 'n_estimators': 10}
52885.86715332332 {'max_features': 2, 'n_estimators': 30}
60075.3680329983 {'max_features': 4, 'n_estimators': 3}
52495.01284985185 {'max_features': 4, 'n_estimators': 10}
50187.24324926565 {'max_features': 4, 'n_estimators': 30}
58064.73529982314 {'max_features': 6, 'n_estimators': 3}
51519.32062366315 {'max_features': 6, 'n_estimators': 10}
49969.80441627874 {'max_features': 6, 'n_estimators': 30}
58895.824998155826 {'max_features': 8, 'n_estimators': 3}
52459.79624724529 {'max_features': 8, 'n_estimators': 10}
49898.98913455217 {'max_features': 8, 'n_estimators': 30}
62381.765106921855 {'bootstrap': False, 'max_features': 2, 'n_estimators': 3}
54476.57050944266 {'bootstrap': False, 'max_features': 2, 'n_estimators': 10}
59974.60028085155 {'bootstrap': False, 'max_features': 3, 'n_estimators': 3}
52754.5632813202 {'bootstrap': False, 'max_features': 3, 'n_estimators': 10}
57831.136061214274 {'bootstrap': False, 'max_features': 4, 'n_estimators': 3}
51278.37877140253 {'bootstrap': False, 'max_features': 4, 'n_estimators': 10}

在这个例子中,我们通过设定超参数max_features为 6,n_estimators为 30,得到了最佳方案。对这个组合,RMSE 的值是 49969,这比之前使用默认的超参数的值(52792)要稍微好一些。祝贺你,你成功地微调了最佳模型!

提示:不要忘记,你可以像超参数一样处理数据准备的步骤。例如,网格搜索可以自动判断是否添加一个你不确定的特征(比如,使用转换器CombinedAttributesAdder的超参数add_bedrooms_per_room)。它还能用相似的方法来自动找到处理异常值、缺失特征、特征选择等任务的最佳方法。

将这些信息转换为DataFrame,可以让我们利用pandas强大的数据处理功能来分析模型性能。
pd.DataFrame(grid_search.cv_results_)

# 将这些信息转换为DataFrame,可以让我们利用pandas强大的数据处理功能来分析模型性能。
pd.DataFrame(grid_search.cv_results_)

运行结果:

2、随机搜索

当探索相对较少的组合时,就像前面的例子,网格搜索还可以。但是当超参数的搜索空间很大时,最好使用RandomizedSearchCV。这个类的使用方法和类GridSearchCV很相似,但它不是尝试所有可能的组合,而是通过选择每个超参数的一个随机值的特定数量的随机组合。这个方法有两个优点:

  • 如果你让随机搜索运行,比如 1000 次,它会探索每个超参数的 1000 个不同的值(而不是像网格搜索那样,只搜索每个超参数的几个值)。

  • 你可以方便地通过设定搜索次数,控制超参数搜索的计算量。

模仿前面的网格搜索步骤进行代码编写:

from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint

# 定义参数分布字典param_distribs,它指定了RandomizedSearchCV搜索的超参数及其可能的值。
# 'n_estimators'使用randint函数在1到200之间随机选择一个整数。
# 'max_features'使用randint函数在1到8之间随机选择一个整数。
# 这种分布方式允许RandomizedSearchCV探索这些参数的随机子集,而不是穷举所有可能的组合。
param_distribs = {
    'n_estimators': randint(low=1, high=200),
    'max_features': randint(low=1, high=8),
}

# 创建RandomForestRegressor模型的实例,设置random_state以确保结果的可重复性。
forest_reg = RandomForestRegressor(random_state=42)

# 初始化RandomizedSearchCV,它将执行参数的随机搜索来找到最佳的超参数组合。
# forest_reg是待优化的模型。
# param_distributions是指定的参数分布字典。
# n_iter=10表示RandomizedSearchCV将尝试10种不同的参数组合。
# cv=5表示使用5折交叉验证来评估每种参数组合的性能。
# scoring='neg_mean_squared_error'指定使用负均方误差作为评分标准。
# random_state=42确保随机搜索过程的可重复性。
rnd_search = RandomizedSearchCV(
    estimator=forest_reg, 
    param_distributions=param_distribs,
    n_iter=10, 
    cv=5, 
    scoring='neg_mean_squared_error', 
    random_state=42
)

# 调用fit方法在housing_prepared特征数据集和housing_labels目标值上训练模型。
# RandomizedSearchCV将进行多次训练和验证,以找到最佳的超参数组合。
rnd_search.fit(housing_prepared, housing_labels)

运行结果:

import numpy as np
# 假设rnd_search是已经使用RandomizedSearchCV执行了fit方法的实例。

# cv_results_属性包含了RandomizedSearchCV在随机搜索过程中的详细交叉验证结果。
# 这个属性是一个字典,记录了每次参数组合的交叉验证分数和使用的参数。

# 将cv_results_属性的值赋给cvres变量,这样我们可以更方便地迭代和分析结果。
cvres = rnd_search.cv_results_

# 使用zip函数同时迭代cv_results_中的"mean_test_score"和"params"。
# "mean_test_score"是每次参数组合在测试集上的平均分数(负均方误差)。
# "params"是RandomizedSearchCV为每次迭代选择的参数组合。

# 循环遍历每一次迭代的结果。
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
    # 计算每次迭代的均方根误差(RMSE),方法是取负均方误差的平方根。
    # 由于存储的分数是负均方误差,我们先取其负值,然后求平方根。
    rms = np.sqrt(-mean_score)

    # 打印每次迭代的RMSE和对应的参数组合。
    # 这有助于我们了解不同参数组合下模型的性能,并识别出表现最佳的参数设置。
    print(rms, params)

运行结果:

49117.55344336652 {'max_features': 7, 'n_estimators': 180}
51450.63202856348 {'max_features': 5, 'n_estimators': 15}
50692.53588182537 {'max_features': 3, 'n_estimators': 72}
50783.614493515 {'max_features': 5, 'n_estimators': 21}
49162.89877456354 {'max_features': 7, 'n_estimators': 122}
50655.798471042704 {'max_features': 3, 'n_estimators': 75}
50513.856319990606 {'max_features': 3, 'n_estimators': 88}
49521.17201976928 {'max_features': 5, 'n_estimators': 100}
50302.90440763418 {'max_features': 3, 'n_estimators': 150}
65167.02018649492 {'max_features': 5, 'n_estimators': 2}

3、集成方法

另一种微调系统的方法是将表现最好的模型组合起来。组合(集成)之后的性能通常要比单独的模型要好(就像随机森林要比单独的决策树要好),特别是当单独模型的误差类型不同时。

4、分析最佳模型和它们的误差

通过分析最佳模型,常常可以获得对问题更深的了解。比如,RandomForestRegressor可以指出每个属性对于做出准确预测的相对重要性:

# 假设grid_search是已经使用GridSearchCV执行了fit方法的实例,且已经找到了最佳模型。

# 从GridSearchCV的最佳估计器(best_estimator_)中提取特征重要性。
# 特征重要性是一个数组,其中每个元素代表一个特征对模型预测能力的贡献大小。
# 这个属性通常用于决策树和随机森林等模型,它可以帮助我们了解哪些特征对模型的决策过程最为重要。

# 获取best_estimator_中的feature_importances_属性,这将是一个包含特征重要性分数的数组。
feature_importances = grid_search.best_estimator_.feature_importances_

# 打印特征重要性数组。
# 这有助于我们了解各个特征对模型预测的贡献程度,进而做出特征选择或进一步分析。
feature_importances

运行结果:

array([6.96542523e-02, 6.04213840e-02, 4.21882202e-02, 1.52450557e-02,
       1.55545295e-02, 1.58491147e-02, 1.49346552e-02, 3.79009225e-01,
       5.47789150e-02, 1.07031322e-01, 4.82031213e-02, 6.79266007e-03,
       1.65706303e-01, 7.83480660e-05, 1.52473276e-03, 3.02816106e-03])

将重要性分数和属性名放到一起:

# 定义一个列表extra_attribs,包含额外添加的特征名称。
# 这些特征是通过自定义转换器添加到数据集中的,例如每个家庭的房间数等。
extra_attribs = ["rooms_per_hhold", "pop_per_hhold", "bedrooms_per_room"]

# 获取full_pipeline中用于处理分类属性的转换器,这里使用的是OneHotEncoder。
# 我们通过访问Pipeline的named_transformers_属性来获取转换器实例。
# 这个转换器负责将分类特征转换为独热编码特征。
cat_encoder = full_pipeline.named_transformers_["cat"]

# 从OneHotEncoder实例中获取第一个类别的所有特征名称。
# categories_属性是一个列表,其中包含了每个特征的所有可能类别。
# 由于OneHotEncoder输出的是稀疏矩阵,我们取第一个元素来获取转换后的类别名称。
cat_one_hot_attribs = list(cat_encoder.categories_[0])

# 创建一个包含所有数值特征、额外添加的特征和独热编码特征的列表。
# 这个列表将用于分析特征重要性。
attributes = num_attribs + extra_attribs + cat_one_hot_attribs

# 使用sorted函数和zip函数组合来对特征重要性进行排序。
# 我们首先将特征重要性列表和特征名称列表通过zip函数组合成一个元组列表。
# 然后,使用sorted函数对这个列表进行排序,reverse=True参数表示降序排序,
# 这样最重要的特征将会排在列表的最前面。
sorted_features = sorted(zip(feature_importances, attributes), reverse=True)

# 打印排序后的列表,这有助于我们快速识别对模型预测贡献最大的特征。
sorted_features

运行结果:

[(np.float64(0.3790092248170967), 'median_income'),
 (np.float64(0.16570630316895876), 'INLAND'),
 (np.float64(0.10703132208204355), 'pop_per_hhold'),
 (np.float64(0.06965425227942929), 'longitude'),
 (np.float64(0.0604213840080722), 'latitude'),
 (np.float64(0.054778915018283726), 'rooms_per_hhold'),
 (np.float64(0.048203121338269206), 'bedrooms_per_room'),
 (np.float64(0.04218822024391753), 'housing_median_age'),
 (np.float64(0.015849114744428634), 'population'),
 (np.float64(0.015554529490469328), 'total_bedrooms'),
 (np.float64(0.01524505568840977), 'total_rooms'),
 (np.float64(0.014934655161887772), 'households'),
 (np.float64(0.006792660074259966), '<1H OCEAN'),
 (np.float64(0.0030281610628962747), 'NEAR OCEAN'),
 (np.float64(0.0015247327555504937), 'NEAR BAY'),
 (np.float64(7.834806602687504e-05), 'ISLAND')]

有了这个信息,你就可以丢弃一些不那么重要的特征(比如,显然只要一个ocean_proximity的类型(ISLAND)就够了,所以可以丢弃掉其它的)。

你还应该看一下系统犯的误差,搞清为什么会有些误差,以及如何改正问题(添加更多的特征,或相反,去掉没有什么信息的特征,清洗异常值等等)。

5、用测试集评估系统

调节完系统之后,你终于有了一个性能足够好的系统。现在就可以用测试集评估最后的模型了。这个过程没有什么特殊的:从测试集得到预测值和标签,运行full_pipeline转换数据(调用transform(),而不是fit_transform()!),再用测试集评估最终模型:

from sklearn.metrics import mean_squared_error
import numpy as np

# 假设grid_search是已经使用GridSearchCV执行了fit方法的实例,且已经找到了最佳模型。

# 获取GridSearchCV搜索到的最佳模型实例。
# best_estimator_属性包含了在交叉验证中表现最佳的模型。
final_model = grid_search.best_estimator_

# 从strat_test_set中删除"median_house_value"列,因为这是我们要预测的目标变量。
# 我们将其作为X_test的特征数据集。
X_test = strat_test_set.drop("median_house_value", axis=1)

# 将strat_test_set中的"median_house_value"列复制到y_test,这是我们要预测的目标值。
y_test = strat_test_set["median_house_value"].copy()

# 使用full_pipeline转换测试集X_test,以便为其应用之前定义的所有预处理步骤。
# 这包括选择特征、填充缺失值、构造新特征、标准化和独热编码。
X_test_prepared = full_pipeline.transform(X_test)

# 使用最终模型final_model对转换后的特征数据集X_test_prepared进行预测。
# 存储预测结果到final_predictions。
final_predictions = final_model.predict(X_test_prepared)

# 计算最终模型预测结果的均方误差(MSE)。
final_mse = mean_squared_error(y_test, final_predictions)

# 计算均方误差的平方根,得到均方根误差(RMSE)。
# RMSE提供了预测误差的度量,与原始数据具有相同的单位,更易于直观理解。
final_rmse = np.sqrt(final_mse)

# 打印最终模型的RMSE值,这是衡量模型预测精度的一个重要指标。
print(f"Final RMSE on test set: {final_rmse}")

运行结果:

Final RMSE on test set: 47873.26095812988

评估结果通常要比交叉验证的效果差一点,如果你之前做过很多超参数微调(因为你的系统在验证集上微调,得到了不错的性能,通常不会在未知的数据集上有同样好的效果)。这个例子不属于这种情况,但是当发生这种情况时,你一定要忍住不要调节超参数,使测试集的效果变好;这样的提升不能推广到新数据上。

然后就是项目的预上线阶段:你需要展示你的方案(重点说明学到了什么、做了什么、没做什么、做过什么假设、系统的限制是什么,等等),记录下所有事情,用漂亮的图表和容易记住的表达(比如,“收入中位数是房价最重要的预测量”)做一次精彩的展示。

五、启动、监控、维护系统

很好,你被允许启动系统了!你需要为实际生产做好准备,特别是接入输入数据源,并编写测试。

你还需要编写监控代码,以固定间隔检测系统的实时表现,当发生下降时触发报警。这对于捕获突然的系统崩溃和性能下降十分重要。做监控很常见,是因为模型会随着数据的演化而性能下降,除非模型用新数据定期训练。

评估系统的表现需要对预测值采样并进行评估。这通常需要人来分析。分析者可能是领域专家,或者是众包平台(比如 Amazon Mechanical Turk 或 CrowdFlower)的工人。不管采用哪种方法,你都需要将人工评估的流水线植入系统。

你还要评估系统输入数据的质量。有时因为低质量的信号(比如失灵的传感器发送随机值,或另一个团队的输出停滞),系统的表现会逐渐变差,但可能需要一段时间,系统的表现才能下降到一定程度,触发警报。如果监测了系统的输入,你就可能尽量早的发现问题。对于线上学习系统,监测输入数据是非常重要的。

最后,你可能想定期用新数据训练模型。你应该尽可能自动化这个过程。如果不这么做,非常有可能你需要每隔至少六个月更新模型,系统的表现就会产生严重波动。如果你的系统是一个线上学习系统,你需要定期保存系统状态快照,好能方便地回滚到之前的工作状态。

附录:

一、一些知识点

1、Scikit-Learn 设计

Scikit-Learn 设计的 API 设计的非常好。它的主要设计原则是:

  • 一致性:所有对象的接口一致且简单:

    • 估计器(estimator)。任何可以基于数据集对一些参数进行估计的对象都被称为估计器(比如,imputer就是个估计器)。估计本身是通过fit()方法,只需要一个数据集作为参数(对于监督学习算法,需要两个数据集;第二个数据集包含标签)。任何其它用来指导估计过程的参数都被当做超参数(比如imputerstrategy),并且超参数要被设置成实例变量(通常通过构造器参数设置)。
    • 转换器(transformer)。一些估计器(比如imputer)也可以转换数据集,这些估计器被称为转换器。API 也是相当简单:转换是通过transform()方法,被转换的数据集作为参数。返回的是经过转换的数据集。转换过程依赖学习到的参数,比如imputer的例子。所有的转换都有一个便捷的方法fit_transform(),等同于调用fit()transform()(但有时fit_transform()经过优化,运行的更快)。
    • 预测器(predictor)。最后,一些估计器可以根据给出的数据集做预测,这些估计器称为预测器。例如,上一章的LinearRegression模型就是一个预测器:它根据一个国家的人均 GDP 预测生活满意度。预测器有一个predict()方法,可以用新实例的数据集做出相应的预测。预测器还有一个score()方法,可用于评估测试集(如果是监督学习算法的话,还要给出相应的标签)的预测质量。
  • 可检验。所有估计器的超参数都可以通过实例的公共变量直接访问(比如,imputer.strategy),并且所有估计器学习到的参数也可以通过在实例变量名后加下划线来访问(比如,imputer.statistics_)。

  • 类不可扩散。数据集被表示成 NumPy 数组或 SciPy 稀疏矩阵,而不是自制的类。超参数只是普通的 Python 字符串或数字。

  • 可组合。尽可能使用现存的模块。例如,用任意的转换器序列加上一个估计器,就可以做成一个流水线,后面会看到例子。

  • 合理的默认值。Scikit-Learn 给大多数参数提供了合理的默认值,很容易就能创建一个系统。

二、源码工程

GitHub - XANkui/PythonMachineLearnIntermediateLevel: Python 机器学习是利用 Python 编程语言中的各种工具和库来实现机器学习算法和技术的过程。Python 是一种功能强大且易于学习和使用的编程语言,因此成为了机器学习领域的首选语言之一。这里我们一起开始一场Python 机器学习进阶之旅。

三、该案例的环境 package 信息如下

Package                   Version
------------------------- --------------
anyio                     4.4.0
argon2-cffi               23.1.0
argon2-cffi-bindings      21.2.0
arrow                     1.3.0
asttokens                 2.4.1
async-lru                 2.0.4
attrs                     23.2.0
Babel                     2.15.0
beautifulsoup4            4.12.3
bleach                    6.1.0
certifi                   2024.7.4
cffi                      1.16.0
charset-normalizer        3.3.2
colorama                  0.4.6
comm                      0.2.2
contourpy                 1.2.1
cycler                    0.12.1
debugpy                   1.8.2
decorator                 5.1.1
defusedxml                0.7.1
executing                 2.0.1
fastjsonschema            2.20.0
fonttools                 4.53.1
fqdn                      1.5.1
h11                       0.14.0
httpcore                  1.0.5
httpx                     0.27.0
idna                      3.7
ipykernel                 6.29.5
ipython                   8.26.0
ipywidgets                8.1.3
isoduration               20.11.0
jedi                      0.19.1
Jinja2                    3.1.4
joblib                    1.4.2
json5                     0.9.25
jsonpointer               3.0.0
jsonschema                4.23.0
jsonschema-specifications 2023.12.1
jupyter                   1.0.0
jupyter_client            8.6.2
jupyter-console           6.6.3
jupyter_core              5.7.2
jupyter-events            0.10.0
jupyter-lsp               2.2.5
jupyter_server            2.14.2
jupyter_server_terminals  0.5.3
jupyterlab                4.2.4
jupyterlab_pygments       0.3.0
jupyterlab_server         2.27.3
jupyterlab_widgets        3.0.11
kiwisolver                1.4.5
MarkupSafe                2.1.5
matplotlib                3.9.1
matplotlib-inline         0.1.7
mistune                   3.0.2
nbclient                  0.10.0
nbconvert                 7.16.4
nbformat                  5.10.4
nest-asyncio              1.6.0
notebook                  7.2.1
notebook_shim             0.2.4
numpy                     2.0.1
overrides                 7.7.0
packaging                 24.1
pandas                    2.2.2
pandocfilters             1.5.1
parso                     0.8.4
pillow                    10.4.0
pip                       24.1.2
platformdirs              4.2.2
prometheus_client         0.20.0
prompt_toolkit            3.0.47
psutil                    6.0.0
pure_eval                 0.2.3
pycparser                 2.22
Pygments                  2.18.0
pyparsing                 3.1.2
python-dateutil           2.9.0.post0
python-json-logger        2.0.7
pytz                      2024.1
pywin32                   306
pywinpty                  2.0.13
PyYAML                    6.0.1
pyzmq                     26.0.3
qtconsole                 5.5.2
QtPy                      2.4.1
referencing               0.35.1
requests                  2.32.3
rfc3339-validator         0.1.4
rfc3986-validator         0.1.1
rpds-py                   0.19.1
scikit-learn              1.5.1
scipy                     1.14.0
Send2Trash                1.8.3
setuptools                70.1.1
six                       1.16.0
sniffio                   1.3.1
soupsieve                 2.5
stack-data                0.6.3
terminado                 0.18.1
threadpoolctl             3.5.0
tinycss2                  1.3.0
tornado                   6.4.1
traitlets                 5.14.3
types-python-dateutil     2.9.0.20240316
typing_extensions         4.12.2
tzdata                    2024.1
uri-template              1.3.0
urllib3                   2.2.2
wcwidth                   0.2.13
webcolors                 24.6.0
webencodings              0.5.1
websocket-client          1.8.0
wheel                     0.43.0
widgetsnbextension        4.0.11

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1965274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue使用flex将图片并排居中且左对齐

先看效果&#xff1a; 在看代码 <template><div class"outer"><div class"inner"><div classeach_image v-for"(item,index) in image_list" :key"index"><img class"image_class" src"./…

培训孵化公司必备ERP的系统,跟卖和铺货以及订单物流发货打包

培训孵化必备的 ERP 系统&#xff0c;贴牌定制独立部署&#xff0c;跟卖铺货&#xff0c;物流对接。 说说新手与培训孵化学员如何使用 ERP&#xff01; 1. ERP 系统对于新手来说非常简单且容易操作&#xff0c;上面的跟卖功能很全面。比如铺货方面&#xff0c;可以采集 1688、…

发现SOLIDWORKS设计活页夹

您有没有遇到过将模型文件转交给同事时丢失附件的文档信息的&#xff1f;您有没有遇到过您的业务同事使用您的模型时仍然搞不清模型和业务项目之间的关系&#xff1f; 在纸制图纸的“旧时代”中&#xff0c;会有一整套信息&#xff08;文档或者表格&#xff09;与模型和图纸一…

电路原理--基础电路工具

1.正弦信号激励下的动态电路分析法-----频域相量法 课本第六章269页。 2.阻抗 3.滤波器简单理解 先介绍下滤波&#xff0c;芯片和元器件在相互工作的时候&#xff0c;会相互影响&#xff0c;在线路上产生寄生电阻或者寄生电容&#xff0c;这种现象叫耦合&#xff0c;耦合会带…

2024 巴黎奥运会:科技点亮体育盛会

一、引言 巴黎奥运会作为全球瞩目的体育盛事&#xff0c;承载着深厚的历史与文化底蕴。它不仅是运动员们展现卓越竞技能力的舞台&#xff0c;也是科技成果大放异彩的平台。科技在巴黎奥运会中的地位举足轻重&#xff0c;为赛事的各个方面带来了革新与突破。 从赛事的筹备到运…

Threejs中导入GLTF模型克隆后合并

很多场景中会需要同一个模型很多次&#xff0c;但是如果多次加载同一个模型会占用很高的带宽&#xff0c;导致加载很慢&#xff0c;因此就需要使用clone&#xff0c;也就是加载一个模型后&#xff0c;其他需要使用的地方使用clone的方式复制出多个同样的模型&#xff0c;再改变…

静态路由与默认路由和实验以及ARP工作原理

目录 1.静态路由和默认路由 1.1 静态路由 1.2 默认路由 1.3 主要区别总结 2.实验 2.1 实验 2.1.1 实验top 2.1.2 实验要求 2.2 实验配置 2.2.1 ip信息配置 2.2.2 配置静态 2.2.3配置默认 2.3 实验结果查看 3.为什么第一个ping会显示丢包&#xff1f; 3.1 ARP 工…

15.3 zookeeper实现分布式锁

1. 简介 2. 代码演示 2.1 客户端连接类 package com.ruoyi.common.zookeeper;import com.ruoyi.common.exception.UtilException; import

操作系统-硬件结构学习心得

1. 程序执行基本过程 那CPU执行程序的过程如下: ●第一步&#xff0c;CPU读取[程序计数器」的值&#xff0c;这个值是指令的内存地址&#xff0c;然后CPU的「控制单元操作 「地址总线」指定需要访问的内存地址&#xff0c;接着通知内存设备准备数据&#xff0c;数据准备好后通…

【每日刷题】Day90

【每日刷题】Day90 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 单词缩写_牛客题霸_牛客网 (nowcoder.com) 2. 面试题 01.03. URL化 - 力扣&#xff08;LeetCode&am…

深度剖析Google黑科技RB-Modulation:告别繁琐训练,拥抱无限创意生成和风格迁移!

给定单个参考图像,RB-Modulation提供了一个无需训练的即插即用解决方案,用于(a)风格化和(b)具有各种提示的内容样式组合,同时保持样本多样性和提示对齐。例如,给定参考样式图像(例如“熔化的黄金3d渲染样式”)和内容图像(例如(a)“狗”),RB-Modulation方法可以坚持所需的提…

内存泄漏 与 内存溢出

1.内存溢出(Memory Overflow) 生活样例&#xff1a; 内存容量就像一个桶&#xff0c;内存就是水&#xff0c;水 溢出 就是水满了。定义: 内存溢出是指程序试图使用超过其可用内存限制的内存。这种情况通常会导致程序崩溃或异常。内存溢出一般是由于分配了过多…

Mixture of Experts with Attention论文解读

注意这篇论文没有代码&#xff0c;文章所谓的注意力是加性注意力&#xff0c;找scaled dot-product的伙计可以避坑了&#xff0c;但还是有值得学习的地方。 score是啥&#xff1f; 这个score标量怎么计算得到&#xff0c;请假设一下x和z的值&#xff0c;计算演示一下 expert是…

第十二章(重点 元数据管理)

语境关系图&#xff1a; 1. 元数据概念&#xff1a; 元数据从技术的角度叫元数据 从业务的角度叫数据资源管理目录 技术 元数据 业务 数据资源管理目录 但是并不是数据资产目录 如果没有可靠的原数据&#xff0c;组织就不知道它拥有什么数据&#xff0c;数据表示什么&#xff…

运行ruoyi

创建数据库 根据ry_20240629.sql创建ry-cloud数据库 根据ry_config_20231204.sql创建ry-config数据库 nacos 数据库配置 修改nacos/conf/application.properties 单机版运行 startup.cmd -m standalone redis 运行后端 运行gateway,auth,modules/system模块 可能遇到的问…

怎么给电脑选一款合适的固态硬盘?就看这个参数!

前言 前段时间有很多小伙伴找小白修电脑&#xff0c;在修电脑的过程中&#xff0c;小白也会稍微看一下硬件配置。 小白就发现一个事情&#xff1a;很多小伙伴其实都不太懂电脑硬件。 为啥这么说呢&#xff1f;简单来说就是主板上使用了“不合适”的固态硬盘作为主系统硬盘。…

VulnHub-Tomato靶机渗透教程 简单易懂 报错链接

Tomato靶机是一个用于渗透测试和漏洞研究的虚拟机。 环境准备 攻击机&#xff08;Kali Linux&#xff09;IP&#xff1a;192.168.252.134 目标机 IP&#xff1a;192.168.252.133 这里我两台虚拟机都是NAT模式 渗透步骤 1.端口扫描 这里我没用kali自带的 我用的物理机上…

【Python学习手册(第四版)】学习笔记12.1-语法规则拓展

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文是对【学习笔记10】-语句编写的通用规则 介绍过的语法概念进行复习并扩展。非常简单&#xff0c;应该是我写过的最简单的文章&#xff0c;阅读时间&#xff1a…

学习Mybatis及其简单配置

目录 JDBC的弊端 为什么要有ORM模型&#xff1f; 什么是ORM模型&#xff1f; Mybatis和hibernate 区别: Mybatis解决了jdbc的问题 为什么选择myBatis&#xff08;优势&#xff09;&#xff1f; 什么是MyBatis 主配置文件&#xff08;config文件&#xff09; Mapper文件…

TwinCAT3 C++环境安装教程

文章目录 下载windos插件:下载地址&#xff0c;安装这个插件是为了能在 TwinACT 3 工程环境创建和编辑 C模块。 点击下载的文件&#xff0c;打开其中的KitSetup.exe 在打开的窗口中选择"Build Environment"后点击OK 弹出的窗口点击ok 选择“I agree”后点击…