特征缩放和转换以及自定义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.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(),
transformer=StandardScaler())
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_func=np.exp)
log_pop = log_transformer.transform(housing[["population"]])

inverse_func参数是可选的。它允许您指定一个逆变换函数,例如,如果您计划在
TransformedTargetRegressor中使用您的转换器。转换函数可以接受超参数作为附加参数。例如,以下是如何创建一个转换器,计算与前面相同的高斯RBF相似性度量:

rbf_transformer = FunctionTransformer(rbf_kernel,
kw_args=dict(Y=[[35.]], gamma=0.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_args=dict(Y=[sf_coords], gamma=0.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_mean=True): # no *args or **kwargs!self.with_mean = with_meandef fit(self, X, y=None): # y is required even though we don't use itX = check_array(X) # checks that X is an array with finite float valuesself.mean_ = X.mean(axis=0)self.scale_ = X.std(axis=0)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_clusters=10, gamma=1.0, random_state=None):self.n_clusters = n_clustersself.gamma = gammaself.random_state = random_statedef fit(self, X, y=None, sample_weight=None):self.kmeans_ = KMeans(self.n_clusters, random_state=self.random_state)self.kmeans_.fit(X, sample_weight=sample_weight)return self # always return self!def transform(self, X):return rbf_kernel(X, self.kmeans_.cluster_centers_, gamma=self.gamma)def get_feature_names_out(self, names=None):return [f"Cluster {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_clusters=10, gamma=1., random_state=42)
similarities = cluster_simil.fit_transform(housing[["latitude", "longitude"]],
sample_weight=housing_labels)

这段代码创建一个ClusterSimilarity转换器,将集群数设置为10.然后调用fit_transform(),输入训练集中每个区的纬度和经度,并根据每个区的房屋中值对每个区进行加权。变压器采用k-均值定位聚类,
然后测量每个区域与所有10个聚类中心之间的高斯RBF相似性。结果是一个矩阵,每个区有一行,每个集群有一列。先看前三行,四舍五入到小数点后两位:

在这里插入图片描述

下图显示了通过k-means找到的10个聚类中心。根据它们与最近的集群中心的地理相似性,对这些区域进行着色。正如您所看到的,大多数集群都位于人口密集且价格昂贵的地区。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Axure RP Pro 8 mac/win中文版:打造无限可能的原型设计工具

在如今的数字化时代,原型设计工具越来越受到设计师和产品经理们的重视。而Axure RP Pro8作为一款强大的原型设计工具,成为了众多专业人士的首选。 首先,Axure RP Pro8具备丰富的功能。它提供了多种交互元素和动画效果,使得用户可…

scapy No such device exists (No such device exists)

使用python编写一个小的网络程序时,程序如下: import scapy.all as scapydef scan(ip):arp_request ARP(pdstip)arp_request.show()broadcast scapy.Ether(dst "ff:ff:ff:ff:ff:ff")arq_request_broadcast broadcast/arp_requestanswered,…

DGL创建异构图

利用DGL创建具有3种节点类型和3种边类型的异构图 graph_data {# (src_type, edge_type, dst_type)(drug, interacts, drug): (th.tensor([0, 1]), th.tensor([1, 2])),(drug, interacts,, disease): (th.tensor([1]), th.tensor([2])) }g dgl.heterograph(graph_data)上述代…

cmake+OpenCV4.8.0+contrib4.8.0+cuda 12.2编译踩坑

cmakeOpenCV4.8.0contrib4.8.0cuda 12.2编译踩坑 准备工具 cmake (去官网下载)OpenCV 我下载的是官网发布最新的稳定版本对应的源码,官网目前是4.8.0,github下一个(连不上的可以网上找找资源或者科学上网&#xff09…

wpf devexpress Property Grid创建属性定义

WPF Property Grid控件使用属性定义定义如何做和显示 本教程示范如何绑定WP Property Grid控件到数据和创建属性定义。 执行如下步骤 第一步-创建属性定义 添加PropertyGridControl组件到项目。 打开工具箱在vs,定位到DX.23.1: Data 面板,选择Prope…

亚马逊云科技AI创新应用下的托管在AWS上的数据可视化工具—— Amazon QuickSight

目录 Amazon QuickSight简介 Amazon QuickSight的独特之处 Amazon QuickSight注册 Amazon QuickSight使用 Redshift和Amazon QuickSightt平台构建数据可视化应用程序 构建数据仓库 数据可视化 Amazon QuickSight简介 亚马逊QuickSight是一项可用于交付的云级商业智能 (BI…

Docker在Centos7下的安装

1、卸载旧版本 执行如下指令对旧版本进行卸载: sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 执行完毕后,如果输入docker version发现do…

js计算某个时间距离现在有几年几月几日几分几秒之前的方法

数据类型 使用js时间戳 console.log(Date.now()) //1642471441587 或者转化为时间戳才能使用 Date.parse(“2022/1/18 10:05”) //1642471500000 将时间戳转化成时间格式的方法如下–链接查看 https://mp.weixin.qq.com/s?__bizMjM5MDA2MTI1MA&mid2649121025&idx2&am…

android studio导入eclipse项目

网上下载一个老工程,.project文件里有eclipse。 android studio导入eclipse项目 eclipse项目结构 Android studio文件结构 下面是导入步骤: 第一步,打开一个项目。 选择File->New->Import Project 第二步,选择Eclipse项目根…

NX二次开发UF_CAM_ask_doc_template_name 函数介绍

文章作者:里海 来源网站:里海NX二次开发3000例专栏 UF_CAM_ask_doc_template_name Defined in: uf_cam.h int UF_CAM_ask_doc_template_name(const char * * doc_template_filename ) overview 概述 This function provides the name of the file th…

Linux mmap 的作用是什么?

文章目录 1.简介2.相关函数3.mmap和常规文件操作的区别4.作用参考文献 1.简介 mmap&#xff08;memory map&#xff09;即内存映射&#xff0c;用于将一个文件或其它对象映射到进程的地址空间。 2.相关函数 创建映射函数&#xff1a; #include <sys/mman.h>void *mm…

浅谈 JVM GC 收集器--系列(一)

又到一年大促时刻&#xff0c;今天我们一起探讨下JVM垃圾回收的问题&#xff0c;写代码的时候想一想如何减少FullGC问题的出现&#xff0c;因为一旦出现频繁FullGC&#xff0c;短时间内没有太好的解决办法&#xff0c;很有可能重启后服务接着FullGC&#xff0c;导致服务可用率降…

【运维篇】Redis常见运维命令详解

文章目录 1. 前言2. 连接管理命令详解2.1 AUTH命令2.2 PING命令2.3 SELECT命令2.4 QUIT命令 3. 服务器管理命令详解3.1 FLUSHALL命令3.2 SAVE/BGSAVE命令3.3 SHUTDOWN命令 4. 安全管理命令详解4.1 CONFIG命令4.1.1 CONFIG SET命令用法4.1.2 CONFIG GET命令用法 4.2 AUTH命令 5.…

海外代理IP如何找到靠谱的?

现在市面上有很多代理服务商&#xff0c;大家可以根据自己的需求选择一个适合自己业务的的IP代理服务商&#xff0c;现在也有一些免费的&#xff0c;但如果力求稳定安全&#xff0c;还是选择付费的。 这里提醒一句&#xff0c;在买代理IP时最好找这种可以免费试用的&#xff0…

kernel32.dll丢失都有什么解决办法,帮助大家解决kernel32.dll丢失的问题

kernel32.dll丢失是电脑中常出现的情况&#xff0c;今天就想和大脚聊聊这个kernel32.dll 文件&#xff0c;这个文件它的功能是干什么的&#xff0c;如果电脑中kernel32.dll 丢失都有什么解决办法&#xff0c;帮助大家解决kernel32.dll丢失的问题&#xff0c;本篇文章给大家提供…

鸿蒙:Harmony开发基础知识详解

一.概述 工欲善其事&#xff0c;必先利其器。 上一篇博文实现了一个"Hello Harmony"的Demo&#xff0c;今天这篇博文就以"Hello Harmony" 为例&#xff0c;以官网开发文档为依据&#xff0c;从鸿蒙开发主要的几个方面入手&#xff0c;详细了解一下鸿蒙开…

MIUI查看当前手机电池容量

MIUI查看当前手机电池容量 1. 按如下步骤操作生成bug报告 2. 按如下操作解压bug报告 Last learned battery capacity

分布式服务与分布式框架

分布式副武其实就是根据某个粒度&#xff0c;将服务拆分&#xff0c;而分布式框架就是将这些服务协调&#xff0c;管理起来。分布式框架&#xff0c;我认为服务调用是他的基础能力&#xff0c;该能力是所有分布式框架的基础能力&#xff0c;其次是服务注册与发现。 在这个维度…

TCP与UDP协议

TCP与UDP协议 1、TCP协议&#xff1a; 1、TCP特性&#xff1a; TCP 提供一种面向连接的、可靠的字节流服务。在一个 TCP 连接中&#xff0c;仅有两方进行彼此通信。广播和多播不能用于 TCP。TCP 使用校验和&#xff0c;确认和重传机制来保证可靠传输。TCP 给数据分节进行排序…