静态网站开发工具有哪些,wordpress去掉页脚,wordpress ajax本地化,郑州移动端网站建设特征缩放和转换
您需要应用于数据的最重要的转换之一是功能扩展。除了少数例外#xff0c;机器学习算法在输入数值属性具有非常不同的尺度时表现不佳。住房数据就是这种情况:房间总数约为6至39320间#xff0c;而收入中位数仅为0至15间。如果没有任何缩放#xff0c;大多数…特征缩放和转换
您需要应用于数据的最重要的转换之一是功能扩展。除了少数例外机器学习算法在输入数值属性具有非常不同的尺度时表现不佳。住房数据就是这种情况:房间总数约为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]], gamma0.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.fit_transform(housing_labels.to_frame())
model LinearRegression()
model.fit(housing[[median_income]], scaled_labels)
some_new_data housing[[median_income]].iloc[:5] # pretend this is new data
scaled_predictions model.predict(some_new_data)
predictions target_scaler.inverse_transform(scaled_predictions)这工作得很好但更简单的选择是使用TransformedTargetRegressor。我们只需要构造它给它回归模型和标签转换器然后使用原始的未缩放标签将其拟合到训练集上。它将自动使用转换器缩放标签并在缩放后的标签上训练回归模型就像我们之前所做的那样。然后当我们想要进行预测时它将调用回归模型的predict()方法并使用scaler的inverse_trans form()方法生成预测:
from sklearn.compose import TransformedTargetRegressor
model TransformedTargetRegressor(LinearRegression(),
transformerStandardScaler())
model.fit(housing[[median_income]], housing_labels)
predictions model.predict(some_new_data)自定义Transformers
虽然Scikit-Learn提供了许多有用的转换器但您需要编写自己的任务如自定义转换、清理操作或组合特定属性。
对于不需要任何训练的转换您可以只编写一个函数该函数接受NumPy数组作为输入并输出转换后的数组。例如如前一节所述通过将具有重尾分布的特征替换为它们的对数(假设特征为正数且尾部位于右侧)通常是一个好主意。让我们创建一个log-transformer并将其应用于人口特征:
from sklearn.preprocessing import FunctionTransformer
log_transformer FunctionTransformer(np.log, inverse_funcnp.exp)
log_pop log_transformer.transform(housing[[population]])inverse_func参数是可选的。它允许您指定一个逆变换函数例如如果您计划在 TransformedTargetRegressor中使用您的转换器。转换函数可以接受超参数作为附加参数。例如以下是如何创建一个转换器计算与前面相同的高斯RBF相似性度量:
rbf_transformer FunctionTransformer(rbf_kernel,
kw_argsdict(Y[[35.]], gamma0.1))
age_simil_35 rbf_transformer.transform(housing[[housing_median_age]]注意RBF核没有反函数因为在距离一个固定点的给定距离上总是有两个值(距离0除外)。还要注意rbf_kernel()不会单独处理这些特性。如果你给它传递一个有两个特征的数组它会测量二维距离(欧几里得)来测量相似性。例如以下是如何添加一个功能该功能将测量每个区和旧金山之间的地理相似性:
sf_coords 37.7749, -122.41
sf_transformer FunctionTransformer(rbf_kernel,
kw_argsdict(Y[sf_coords], gamma0.1))
sf_simil sf_transformer.transform(housing[[latitude, longitude]])自定义transformers对于组合功能也很有用。例如这里有一个FunctionTransformer它计算输入特征0和1之间的比率: FunctionTransformer非常方便但是如果您希望您的转换器是可训练的在fit()方法中学习一些参数然后在transform()方法中使用它们那该怎么办呢?为此您需要编写一个自定义类。Scikit-Learn依赖于duck类型所以这个类不必从任何特定的基类继承。它只需要三个方法:fit()(必须返回self)、 transform () 和fit_transform()。
只需添加TransformerMixin作为基类就可以免费获得fit_transform():默认实现将只调用fit()然后再调用transform()。如果将BaseEstimator添加为基类(并避免使用*args和**kwargs)您还将获得两个额外的方法:get_params ()和set_params()。这些对于自动超参数调优非常有用。
例如这里有一个自定义 transformer其行为与StandardScaler非常相似:
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_array, check_is_fitted
class StandardScalerClone(BaseEstimator, TransformerMixin):def __init__(self, with_meanTrue): # no *args or **kwargs!self.with_mean with_meandef fit(self, X, yNone): # y is required even though we dont use itX check_array(X) # checks that X is an array with finite float valuesself.mean_ X.mean(axis0)self.scale_ X.std(axis0)self.n_features_in_ X.shape[1] # every estimator stores this in fit()return self # always return self!def transform(self, X):check_is_fitted(self) # looks for learned attributes (with trailing _)X check_array(X)assert self.n_features_in_ X.shape[1]if self.with_mean:X X - self.mean_return X / self.scal这里有几点需要注意:
sklearn.utils.validation包包含几个我们可以用来验证输入的函数。为了简单起见我们将在本书的其余部分跳过这样的测试但是产品代码应该有这些测试。Scikit-Learn管道要求fit()方法有两个参数X和y这就是为什么我们需要y没有参数即使我们不使用y。所有Scikit-Learn估计器都在fit()方法中设置n_features_in_并且它们确保传递给transform()或predict()的数据具有此数量的特征。_.fit ()方法必须返回self。这个实现不是100%完成的:所有的估算器都应该在拟合中设置feature_ names_in_ ()方法时它们被传递一个DataFrame。此外所有的转换器都 应该提供get_feature_names_out()方法以及当它们的转换可以被逆转时 的inverse_transform()方法。更多细节请参见本章最后一个练习。
自定义转换器可以(而且经常)在其实现中使用其他估计器。例如以下代码演示了自定义转换器该转换器在fit()方法中使用KMeans聚类器来识别训练数据中的主要聚类然后在transform()方法中使用rbf kernel ()来衡量每个样本与每个聚类中心的相似程度:
from sklearn.cluster import KMeans
class ClusterSimilarity(BaseEstimator, TransformerMixin):def __init__(self, n_clusters10, gamma1.0, random_stateNone):self.n_clusters n_clustersself.gamma gammaself.random_state random_statedef fit(self, X, yNone, sample_weightNone):self.kmeans_ KMeans(self.n_clusters, random_stateself.random_state)self.kmeans_.fit(X, sample_weightsample_weight)return self # always return self!def transform(self, X):return rbf_kernel(X, self.kmeans_.cluster_centers_, gammaself.gamma)def get_feature_names_out(self, namesNone):return [fCluster {i} similarity for i in range(self.n_clusters)]k-means是一种在数据中定位聚类的聚类算法。它搜索的数量由n_clusters超参数控制。训练后可以通过cluster_centers_属性使用聚类中心。KMeans的fit()方法支持一个可选参数sample_weight该参数允许用户指定样本的相对权重。K-means是一种随机算法这意味着它依赖随机性来定位聚类因此若您想要可重现的结果则必须设置random_state参数。正如您所看到的尽管任务很复杂但代码相当简单。现在让我们使用这个自定义的变压器:
cluster_simil ClusterSimilarity(n_clusters10, gamma1., random_state42)
similarities cluster_simil.fit_transform(housing[[latitude, longitude]],
sample_weighthousing_labels)这段代码创建一个ClusterSimilarity转换器将集群数设置为10.然后调用fit_transform()输入训练集中每个区的纬度和经度并根据每个区的房屋中值对每个区进行加权。变压器采用k-均值定位聚类 然后测量每个区域与所有10个聚类中心之间的高斯RBF相似性。结果是一个矩阵每个区有一行每个集群有一列。先看前三行四舍五入到小数点后两位: 下图显示了通过k-means找到的10个聚类中心。根据它们与最近的集群中心的地理相似性对这些区域进行着色。正如您所看到的大多数集群都位于人口密集且价格昂贵的地区。