侧边栏壁纸
博主头像
秋码记录

一个游离于山间之上的Java爱好者 | A Java lover living in the mountains

  • 累计撰写 124 篇文章
  • 累计创建 261 个标签
  • 累计创建 42 个分类

微调模型(Machine Learning 研习之十二)

现在正处于百模乱战的时期,对于模型微调,想必您是有所了解了,毕竟国外的大语言模型一开源,国内便纷纷基于该模型进行微调,从而开始宣称领先于某某、超越了谁。可到头来,却让人发现他们套壳了国外大语言模型对外开放的API。

好了,我们不说国内各种大模型宣称超过了谁,毕竟,嘴巴长在别人脸上,我们管不了,也管不着,吹牛终将是会露馅的!

当我们需要对开源大模型进行微调时,看看有几种方法可以做到这一点的!

网格搜索

手动调整超参数,直到找到超参数值的完美组合。 这将是一项非常乏味的工作,而且您可能没有时间去探索多种组合。

相反,您可以使用 Scikit-LearnGridSearchCV 类来搜索您。 您需要做的就是告诉它您希望它试验哪些超参数以及要尝试哪些值,它将使用交叉验证来评估超参数值的所有可能组合。 例如,以下代码搜索 RandomForestRegressor 的最佳超参数值组合:

from sklearn.model_selection import GridSearchCV

full_pipeline = Pipeline([    ("preprocessing", preprocessing),    ("random_forest",                RandomForestRegressor(random_state=42)), ]) 
param_grid = [{'preprocessing__geo__n_clusters': [5, 8, 10],                                       'random_forest__max_features': [4, 6, 8]},    
              {'preprocessing__geo__n_clusters': [10, 15],                                        'random_forest__max_features': [6, 8, 10]}, ] 
grid_search = GridSearchCV(full_pipeline, param_grid, cv=3,                                       scoring='neg_root_mean_squared_error') 
grid_search.fit(housing, housing_labels) 

请注意,您可以引用管道中任何估计器的任何超参数,即使该估计器嵌套在多个管道和列转换器的深处。 例如,当 Scikit-Learn 看到“preprocessing__geo__n_clusters”时,它会在双下划线处分割该字符串,然后在管道中查找名为“preprocessing”的估计器并找到预处理 ColumnTransformer。 接下来,它在此 ColumnTransformer 中查找名为“geo”的转换器,并找到我们在纬度和经度属性上使用的 ClusterSimilarity 转换器。 然后它找到该变压器的n_clusters超参数。 同样,random_forest__max_features指的是名为“random_forest”的估计器的max_features超参数,这当然是RandomForest模型。

这个param_grid中有两个字典,因此GridSearchCV将首先评估第一个字典中指定的n_clustersmax_features超参数值的所有3×3=9个组合,然后它将尝试第一个字典中指定的所有2×3=6个超参数值组合 第二个字典。 因此,网格搜索总共将探索 9 + 6 = 15 种超参数值组合,并且每个组合都会对管道进行 3 次训练,因为我们使用的是 3 折交叉验证。 这意味着总共将有 15 × 3 = 45 轮训练! 这可能需要一段时间,但是完成后您可以获得如下参数的最佳组合:

grid_search.best_params_ {'preprocessing__geo__n_clusters': 15, 'random_forest__max_features': 6} 

您可以使用 grid_search.best_estimator_ 访问最佳估计器。 如果 GridSearchCV 使用refit=True(这是默认值)进行初始化,那么一旦它使用交叉验证找到最佳估计器,它就会在整个训练集上重新训练它。 这通常是一个好主意,因为向其提供更多数据可能会提高其性能。

评估分数可使用 grid_search.cv_results_ 获得。 这是一个字典,但如果将其包装在 DataFrame中,您将获得每个超参数组合和每个交叉验证分割的所有测试分数的良好列表,以及所有分割的平均测试分数:

最佳模型的平均测试 RMSE 分数为 44,042,这比您之前使用默认超参数值获得的分数(47,019)要好。 恭喜,您已成功微调您的最佳模型!

随机搜索

当您探索相对较少的组合时(如前面的示例所示),网格搜索方法很好,但 RandomizedSearchCV 通常更可取,特别是当超参数搜索空间很大时。 该类的使用方式与 GridSearchCV 类大致相同,但它不是尝试所有可能的组合,而是评估固定数量的组合,在每次迭代时为每个超参数选择一个随机值。 这听起来可能令人惊讶,但这种方法有几个好处:

  • 如果您的某些超参数是连续的(或离散的,但有许多可能的值),并且您让随机搜索运行例如 1,000 次迭代,那么它将为每个超参数探索 1,000 个不同的值,而网格搜索只会探索 您为每个值列出的几个值。
  • 假设某个超参数实际上没有太大影响,但您还不知道。 如果它有 10 个可能的值,并将其添加到网格搜索中,那么训练时间将延长 10 倍。 但如果将其添加到随机搜索中,则不会有任何区别。
  • 如果有6 个超参数需要探索,每个超参数都有10 个可能的值,那么网格搜索除了训练模型一百万次之外别无选择,而随机搜索始终可以运行您选择的任意次数的迭代。

对于每个超参数,您必须提供可能值的列表或概率分布:

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

param_distribs = {'preprocessing__geo__n_clusters': randint(low=3, high=50),                  'random_forest__max_features': randint(low=2, high=20)}

rnd_search = RandomizedSearchCV(    full_pipeline,                                               param_distributions=param_distribs, n_iter=10, cv=3,                                 scoring='neg_root_mean_squared_error', random_state=42)

rnd_search.fit(housing, housing_labels) 

Scikit-Learn 还具有 HalvingRandomSearchCVHalvingGridSearchCV 超参数搜索类。 他们的目标是更有效地使用计算资源,要么更快地训练,要么探索更大的超参数空间。 它们的工作原理如下:在第一轮中,使用网格方法或随机方法生成许多超参数组合(称为“候选者”)。 然后,像往常一样,这些候选者被用来训练模型,并使用交叉验证进行评估。 然而,训练使用的资源有限,这大大加快了第一轮的速度。 默认情况下,“有限资源”意味着模型在训练集的一小部分上进行训练。 然而,其他限制也是可能的,例如,如果模型具有超参数来设置它,则减少训练迭代的次数。 一旦每个候选人都经过评估,只有最好的候选人才能进入第二轮,在那里他们将获得更多资源来竞争。 经过几轮之后,最终的候选人将使用全部资源进行评估。 这可能会节省您一些调整超参数的时间。

解决 github.com port 443: Timed out 的问题
« 上一篇 2024-01-27
微调模型——续(Machine Learning 研习之十三)
下一篇 » 2024-03-09

相关推荐

  • 花了不到1块5,玩了下全网最火的ChatGPT 2022-12-08 20:59:39 +0800 CST
  • 选择和训练模型(Machine Learning 研习之十一) 2024-01-14 15:50:17 +0800 CST
    选择和训练模型(Machine Learning 研习之十一) 当您看到本文标题时,不禁感叹,总算是到了训练模型这一节了。 是啊,在之前的文章中,我们对数据进行了探索,以及对一个训练集和一个测试集进行了采样,也编写了一个预处理管道来自动清理,准备您的数据用于机器学习算法,然而现在,我们可以选择并训练模型了。 训练集的训练与评估 我们从一个最基本的线性回归模型开始: from sklearn.linear_model import LinearRegression lin_reg = make_pipeline(preprocessing, LinearRegression()) lin_reg.fit(housing, housing_labels) 很好,至此,我们现在算是有了一个有效的线性回归模型,可以在训练集上试用它,查看前五个预测,并将它们与标签进行比较:: 第一个预测偏差很大(超过200,000美元!),而其他预测则更好,两个预测偏差约25%,还有两个预测 偏差不到10%。请记住,您选择使用RMSE作为性能测度,因此您希望使用Scikit-Learn的mean_squared_error()函数在整个训练集上测量该回归模型的RMSE,并将平方参数设置为False。 这总比没有好,但显然不是一个很好的分数,大多数地区的房屋价值中位数在120,000美元和26.5万美元之间,所以一个典型的68628美元的预测误差真的不是很令人满意。这是一个模型拟合训练数据不足的示例。当这种情况发生时,可能意味着这些特征没有提供足够的信息来做出好的预测,或者模型不够强大。 正如我们在上一章中看到的,修复欠拟合的主要方法是选择一个更强大的模型,为训练算法提供更好的特征,或者减少对模型的约束。这个模型没有正规化,这就排除了最后一个选项。您可以尝试添加更多功能,但首先您要尝试更复杂的模型,看看它是如何工作的。 您决定尝试DecisionTreeRegressor,因为这是一个相当强大的模型,能够在数据中找到复杂的非线性关系(后续篇章将更详细地介绍决策树): from sklearn.tree import DecisionTreeRegressor tree_reg = make_pipeline(preprocessing, DecisionTreeRegressor(random_state=42)) tree_reg.fit(housing, housing_labels) 现在模型已训练完毕,您可以在训练集中对其进行评估: 等等,难道这个模型真的很完美吗?当然咯,更有可能的是模型严重地过度拟合了数据。您怎么能确定正如你前面看到的,在您准备好启动一个您有信心的模型之前,您不想碰测试集,所以您需要使用一部分训练集进行训练,另一部分用于模型验证。 使用交叉验证进行更好的评估 评估决策树模型的一种方法是使用train_test_split()函数将训练集拆分为较小的训练集和验证集,然后针对较小的训练集训练您的模型,并针对验证集对其进行评估。这是一点努力,但没有太难,它会工作得相当不错。 一个很好的替代方法是使用Scikit-Learn的k_-fold交叉验证特性。下面的代码随机地将训练集分成10个不重叠的子集,称为fold,然后训练和评估决策树模型10次,每次选择不同的fold进行评估,并使用其他9个fold进行训练。结果是一个包含10个评价分数的数组: from sklearn.model_selection import cross_val_score tree_rmses = -cross_val_score(tree_reg, housing, housing_labels, scoring="neg_root_mean_squared_error", cv=10) 警告: Scikit-Learn的交叉验证功能期望的是效用函数(越大越好)而不是成本函数(越低越好),所以评分函数实际上是RMSE的反面。它是一个负值,所以您需要切换输出的符号来获得RMSE分 数。 让我们来看看结果吧: 现在决策树看起来不像以前那么好了。事实上,它的表现几乎和线性回归模型一样差!请注意,交叉验证不仅允许您获得模型性能的估计值,还允许您测量该估计值的精确度(即其标准差)。决策树的均方根误差约为66,868,标准差约为2,061。如果只使用一个验证集,则不会有此信息。但是交叉验证是以多次训练模型为代价的,所以它并不总是可行的。 如果您为线性回归模型计算相同的度量,您将发现平均RMSE为69,858,标准差为4,182。因此,决策树模型的性能似乎比线性模型稍微好一点,但由于严重的过拟合,差异很小。我们知道存在过拟合 问题,因为训练误差很低(实际上为零),而验证误差很高。 现在让我们尝试最后一个模型:随机森林调节器,随机森林的工作原理是在特征的随机子集上训练许多决策树,然后平均出它们的预测值。这样的模型组成的许多其他模型被称为合奏:他们能够提高性能基础模型(在本例中为决策树)。代码与前面的代码大同小异: from sklearn.ensemble import RandomForestRegressor forest_reg = make_pipeline(preprocessing, RandomForestRegressor(random_state=42)) forest_rmses = -cross_val_score(forest_reg, housing, housing_labels, scoring="neg_root_mean_squared_error", cv=10) 随机森林真的看起来非常有前途的任务!但是,如果您训练一个RandomForest并测量训练集上的RMSE,您将发现大约17,474:这要低得多,这意味着仍然存在大量的过度拟合。可能的解决方案是 简化模型,约束它(即,规则化它),或得到更多的训练数据。但是,在深入研究随机森林之前,您应该尝试来自各种类别机器学习算法的许多其他模型(例如,具有不同内核的多个支持向量机,可能还有一个神经网络),而无需花费太多时间调整超参数。目标是列出几个(两到五个)有前途的模型。
  • 机器学习中的 Transformation Pipelines(Machine Learning 研习之十) 2023-12-11 19:50:17 +0800 CST
    机器学习中的 Transformation Pipelines(Machine Learning 研习之十) Transformation Pipelines 有许多数据转换步骤需要以正确的顺序执行。幸运的是,Scikit-Learn提供了Pipeline类来帮助处理这样的转换序列。下面是一个用于数值属性的小管道,它首先对输入特性进行归并,然后对输入特性进行缩放: from sklearn.pipeline import Pipeline num_pipeline = Pipeline([ ("impute", SimpleImputer(strategy="median")), ("standardize", StandardScaler()), ]) Pipeline构造函数采用名称/估算器对(2元组)的列表,定义了一系列步骤。名称可以是您喜欢的任何名称,只要它们是唯一的,并且不包含双下划线(__)。以后我们讨论超参数调优时,它们会很有用。估计器必须都是转换器(即,它们必须有一个fit_transform()方法),除了最后一个,它可以是任何东西:转换器、预测器或任何其他类型的估计器。 如果你不想命名transformers你可以使用 make_pipeline() 函数; 它将transformers作为位置参数,并使用transformers类的名称(小写且不带下划线)创建管道(例如,“simpleimputer”): from sklearn.pipeline import make_pipeline num_pipeline = make_pipeline(SimpleImputer(strategy="median"), StandardScaler()) 如果多个transformers具有相同的名称,则会在其名称后附加索引(例如“foo-1”、“foo-2”等)。 当您调用管道的 fit() 方法时,它会在所有transformers上顺序调用 fit_transform(),将每个调用的输出作为参数传递给下一个调用,直到到达最终估计器,为此它只调用 fit() 方法。 该管道公开与最终估计器相同的方法。 在此示例中,最后一个估计器是 StandardScaler,它是一个transformers,因此管道也充当transformers。 如果您调用管道的transform()方法,它将按顺序将所有转换应用于数据。 如果最后一个估计器是预测器而不是变换器,那么管道将具有 Predict() 方法而不是 Transform() 方法。 调用它会按顺序将所有转换应用于数据并将结果传递给预测器的 Predict()方法 让我们调用管道的 fit_transform() 方法并查看输出的前两行,四舍五入到小数点后两位: 如前所述,如果要恢复一个漂亮的DataFrame,可以使用管道的get_feature_names_ out()方法: df_housing_num_prepared = pd.DataFrame( housing_num_prepared, columns=num_pipeline.get_feature_names_out(), index=housing_num.index) 管道支持索引;例如,管道[1]返回管道中的第二个估计值,管道[:-1]返回一个包含除最后一个估计值以外的所有估计值的管道对象。您还可以通过steps属性(它是名称/估算器对的列表)或named_steps字典属性(它将名称映射到估算器)访问估算器。例如,num_line[“ simpleimputer”]返回名为“simpleimputer”的估计器。 到目前为止,我们已经分别处理了分类列和数值列。如果有一个能够处理所有列的转换器,将适当的转换应用到每一列,那会更方便。为此,您可以使用olumnTransformer。例如,下面的ColumnTransformer将把num_pipeline(我们刚刚定义的那个)应用于数字属性,把cat_pipeline应用于类别属性: from sklearn.compose import ColumnTransformer num_attribs = ["longitude", "latitude", "housing_median_age", "total_rooms", "total_bedrooms", "population", "households", "median_income"] cat_attribs = ["ocean_proximity"] cat_pipeline = make_pipeline( SimpleImputer(strategy="most_frequent"), OneHotEncoder(handle_unknown="ignore")) preprocessing = ColumnTransformer([ ("num", num_pipeline, num_attribs), ("cat", cat_pipeline, cat_attribs), ]) 首先导入ColumnTransformer类,然后定义数字和分类列名的列表,并为分类属性构造一个简单的管道。最后,我们构造了一个列变换器。它的构造函数需要一个三元组(3-tuple)列表,每个三元组包含一个名称(必须是唯一的且不包含双下划线)、一个转换器和一个应该应用转换器的列的名称(或索引)列表。
  • 特征缩放和转换以及自定义Transformers(Machine Learning 研习之九) 2023-11-18 20:53:29 +0800 CST
    特征缩放和转换以及自定义Transformers(Machine Learning 研习之九) 特征缩放和转换 您需要应用于数据的最重要的转换之一是功能扩展。除了少数例外,机器学习算法在输入数值属性具有非常不同的尺度时表现不佳。住房数据就是这种情况:房间总数约为6至39320间,而收入中位数仅为0至15间。如果没有任何缩放,大多数模型将倾向于忽略收入中位数,而更多地关注房间数。 有两种常见的方法使所有属性具有相同的尺度:最小-最大尺度和标准化。 与所有估计器一样,重要的是仅将标量拟合到训练数据:永远不要对训练集以外的任何对象使用fit()或fit_transform()。一旦你有了一个训练好的定标器,你就可以用它来变换()任何其他的集合,包括验证集、测试集和新的数据。请注意,虽然培训集值将始终缩放到指定的范围,但如果新的数据包含异常值,则这些值最终可能会缩放到该范围之外。如果要避免这种情况,只需将剪辑超参数设置为True即可。 最小-最大缩放(许多人称之为标准化)是最简单的:对于每个属性,值被移位和重新缩放,以便它们最终的范围从0到1。这是通过减去最小值并除以最小值和最大值之间的差来实现的。Scikit-Learn为此提供了一个名为MinMaxScaler的转换器。它有一个feature_range超参数,如果出于某种原因,不希望0-1(例如,神经网络在零均值输入下工作得最好,所以最好在-1到1的范围内工作)。是相当好用的: from sklearn.preprocessing import MinMaxScaler min_max_scaler = MinMaxScaler(feature_range=(-1, 1)) housing_num_min_max_scaled = min_max_scaler.fit_transform(housing_num) 标准化是不同的:首先它减去平均值(所以标准化值有一个零均值),然后它除以标准差(所以标准-化值的标准差等于1)。不像最小最大缩放,标准化化不会将值限制在特定的范围内。然而,标准化受到离群值的影响要小得多。例如,假设一个地区的收入中位数等于100(误打误撞),而不是通常的0-15。将最小最大值缩放到0-1范围会将这个离群值映射到1并将所有其他值压缩到0-0.15,而标准化不会受到太大影响。Scikit-Learn提供了一个名为StandardScaler的转换器用于标准化: from sklearn.preprocessing import StandardScaler std_scaler = StandardScaler() housing_num_std_scaled = std_scaler.fit_transform(housing_num) 如果你想缩放一个稀疏矩阵而不首先将其转换为稠密矩阵,你可以使用一个标准缩放器,它的with_mean超参数设置为False它只会除以标准差,而不会减去均值(因为这会破坏稀疏性 当特征的分布具有重尾时(即,当远离平均值的值不是指数罕见时),最小-最大缩放和标准化都会将大多数值压缩到一个小范围内。 机器学习模型通常根本不喜欢这种情况,因此,在缩放特征之前,您应该首先对其进行变换以缩小重尾,并且如果可能的话,使分布大致对称。 例如,对于右侧有重尾部的正特征,执行此操作的常见方法是用其平方根替换特征(或将特征提高到 0 到 1 之间的幂)。 如果该特征具有非常长且重的尾部,例如幂律分布,则用其对数替换该特征可能会有所帮助。 例如,人口特征大致遵循幂律:拥有 10,000 名居民的地区的出现频率仅比拥有 1,000 名居民的地区低 10 倍,而不是呈指数级下降。 下图 显示了当你计算它的对数时这个特征看起来有多好:它非常接近高斯分布(即钟形)。 另一种处理重尾特征的方法是对特征进行反向转换。这意味着将其分布切割成大致相等大小的桶,并将每个特征值替换为它所属的桶的索引,就像我们创建收入猫特征一样(尽管我们只在分层抽样时使用它)。例如,您可以将每个值替换为其百分位数。使用相同大小的bucket处理会产生一个几乎均匀分布的特性,因此不需要进一步的缩放,或者您可以只除以bucket的数目来强制值到0-1的范围。 当一个特征具有多峰分布(即,有两个或两个以上清晰的峰值,称为模式)时,例housing_median_age特征,对它进行bucket ization也是有帮助的,但这次将bucket ID作为类别处理,而不是作为数值。这意味着必须对桶索引进行编码,例如使用OneHotEncoder(所以你通常不想用太多桶)。这种方法将允许回归模型更容易地为该特征值的不同范围学习不同的规则。例如,也许35年前建造的房子有一种独特的风格,已经过时了,因此它们比它们的年龄更便宜。 转换多峰分布的另一种方法是为每个模式(至少是主要模式)添加一个特征,表示住房中位年龄和该特定模式之间的相似性。相似性度量通常使用径向基函数(RBF)来计算–任何只依赖于输入值与不动点之间距离的函数。最常用的RBF是高斯RBF,其输出值随着输入值远离固定点而呈指数衰减。例如,高斯RBF相似度与房龄x和35由方程exp (-y (x-35)2)给出。超参数y(gamma)确定当x远离35时相似性度量衰减的速度。使用Scikit-Learn的rbf_kernel()函数,您可以创建一个新的高斯RBF特征来测量房屋中位年龄和35: from sklearn.metrics.pairwise import rbf_kernel age_simil_35 = rbf_kernel(housing[["housing_median_age"]], [[35]], gamma=0.1) 下图显示了这一新特征作为住房中位数年龄的函数(实线)。它还显示了如果使用较小的gamma值,该功能将是什么样子。如图所示,新的年龄相似性特征在35岁时达到峰值,正好在住房中位年龄分布的峰值附近:如果这个特定的年龄组与较低的价格有很好的相关性,那么这个新特征将有很好的机会发挥作用。 到目前为止,我们只看了输入特性,但是目标值可能也需要转换。例如,若目标分布具有较重的尾部,您可以选择将目标替换为其对数。但是,如果你这样做,回归模型现在将预测的房屋价值中位数的对数,而不是房屋价值中位数本身。如果您想要预测的房屋中值,则需要计算模型预测的指数值。 幸运的是,大多数Scikit-Learn的转换器都有一个inverse_transform()方法,这使得计算转换的逆运算变得很容易。例如,下面的代码示例显示了如何使用StandardScaler缩放标签(就像我们对输入所做的那样),然后在缩放后的标签上训练一个简单的线性回归模型,并使用它对一些新数据进行预测,然后使用经过训练的缩放器的inverse_transform()方法将这些数据转换回原始尺度。请注意,我们将标签从Pandas Series转换为DataFrame,因为标准Scaler期望2D输入。此外,为了简单起见,在本示例中,我们仅使用单个原始输入特征(中值收入)对模型进行训练: from sklearn.linear_model import LinearRegression target_scaler = StandardScaler() scaled_labels = target_scaler.
  • 为机器学习算法准备数据(Machine Learning 研习之八) 2023-11-05 11:30:06 +0800 CST
    为机器学习算法准备数据(Machine Learning 研习之八) 本文还是同样建立在前两篇的基础之上的! 属性组合实验 希望前面的部分能让您了解探索数据并获得洞察力的几种方法。您发现了一些数据怪癖,您可能希望在将数据提供给机器学习算法之前对其进行清理,并且发现了属性之间有趣的相关性,特别是与目标属性 之间的相关性。您还注意到一些属性具有向右倾斜的分布,因此您可能需要转换它们(例如,通过计算它们的对数或平方根)。当然,你的里程会因每个项目而有很大的不同,但大致的想法是相似的。 在为机器学习算法准备数据之前,您可能需要做的最后一件事是尝试各种属性组合。例如,如果你不知道一个地区有多少住户,那么这个地区的房间总数就不是很有用。你真正想要的是每个家庭的房间数量。同样,卧室总数本身也不是很有用:你可能想对比一下房间的数量。每个家庭的人口似乎也是一个有趣的属性组合。创建这些新属性如下: housing["rooms_per_house"] = housing["total_rooms"] / housing["households"] housing["bedrooms_ratio"] = housing["total_bedrooms"] / housing["total_rooms"] housing["people_per_house"] = housing["population"] / housing["households"] 然后你再看一遍相关矩阵: !新的bedrooms_ratio属性与房屋中值的相关性要比与房间或卧室总数的相关性大得多。显然,卧室/房间比率较低的房子往往更贵。每个家庭的房间数量也比一个地区的房间总数更能说明问题-很明显,房 子越大,就越贵。 这一轮的探索不需要绝对彻底;关键是从正确的角度出发,并迅速获得见解,这将帮助您获得第一个相当好的原型。但是这是一个迭代的过程:一旦你建立并运行了一个原型,你就可以分析它的输出以获得更多的见解,然后再回到这个探索步骤。 为机器学习算法准备数据 是时候为您的机器学习算法准备数据了。你应该为此编写函数,而不是手工操作,这有几个很好的理由: 这将允许您在任何数据集上轻松重现这些转换(例如,下次获得新数据集时)。 您将逐步构建一个转换函数库,以便在未来的项目中重用。 您可以在实时系统中使用这些函数来转换新数据,然后再将其输入到您的算法中。 这将使您能够轻松地尝试各种转换,并查看哪种转换组合效果最好。 但首先,恢复到一个干净的训练集(通过再次复制strat_train_set)。您还应该将预测变量和标签分开,因为您不一定希望对预测变量和目标值应用相同的转换(请注意,drop()创建数据的副本,并且不影响strat_train_set): housing = strat_train_set.drop("median_house_value", axis=1) housing_labels = strat_train_set["median_house_value"].copy() 清除数据 大多数机器学习算法无法处理缺失的功能,因此您需要处理这些功能。例如,您之前注意到total_bedrooms属性有一些缺失值。你有三个选项可以解决这个问题: 去掉相应的区。 去掉整个属性。 将缺失值设置为某个值(零、均值、中位数等)。这就是所谓的归罪。 您可以使用PandasDataFrame的dropna () 、drop () 和fillna ()方法轻松完成这些任务: housing.dropna(subset=["total_bedrooms"], inplace=True) # option 1 housing.drop("total_bedrooms", axis=1) # option 2 median = housing["total_bedrooms"].median() # option 3 housing["total_bedrooms"].fillna(median, inplace=True) 您决定使用选项3,因为它的破坏性最小,但是您将使用一个方便的Scikit-Learn类:Simplelmputer,而不是前面的代码。这样做的好处是,它将存储每个特征的中值:这将使得它不仅可以估算训练集上的缺失值,还可以估算验证集、测试集和输入到模型的任何新数据上的缺失值。要使用它,首先需要创建一个Simplelmputer实例,指定要将每个属性的缺失值替换为该属性的中位数: from sklearn.