Sklearn标准化和归一化方法汇总(3):范数归一化

news2024/9/23 23:23:12

Sklearn中与特征缩放有关的五个函数和类,全部位于sklearn.preprocessing包内。作为一个系列文章,我们将逐一讲解Sklearn中提供的标准化和归一化方法,以下是本系列已发布的文章列表:

  • Sklearn标准化和归一化方法汇总(1):标准化 / 标准差归一化 / Z-Score归一化
  • Sklearn标准化和归一化方法汇总(2):Min-Max归一化
  • Sklearn标准化和归一化方法汇总(3):范数归一化

以下是Sklearn中的五种与特征缩放相关的函数和类,我们的研究也是为围绕这些函数和类展开的:

名称方法名类名
标准化 / Z-Score 归一化 / 标准差归一化sklearn.preprocessing.scalesklearn.preprocessing.StandardScaler
Min-Max 归一化sklearn.preprocessing.minmax_scalesklearn.preprocessing.MinMaxScaler
范数归一化sklearn.preprocessing.normalizesklearn.preprocessing.Normalizer
Robust Scaler(无常用别名)sklearn.preprocessing.robust_scalesklearn.preprocessing.RobustScaler
Power Transformer (无常用别名)sklearn.preprocessing.power_transformsklearn.preprocessing.PowerTransformer

关于各种关于标准化和归一化的概念和分类,我们已经在此前一篇文章《标准化和归一化概念澄清与梳理》中做了详细的梳理和澄清,不清楚的读者可以先阅读一下此文。本文我们研究第三种归一化手段:范数归一化。本文地址:https://laurence.blog.csdn.net/article/details/128723321,转载请注明出处!

1. 算法

范数归一化的计算逻辑是:先计算出一个向量(通常是一行)的范数(如无特殊说明,通常都是指L-2范数),然后让向量中的每一个元素除以这个范数,得到的新向量就是范数归一化后的结果。所以,理解范数归一化的关键是要理解:范数。我们已经在此前一篇文章中专门做了介绍,请参考《范数的意义与计算方法》一文。

由于范数表示一个向量的“长度”,一个向量除以了自己的“范数”后,就等于把自己的“长度”缩放成了单位长度:1,所以可以想象:在一个二维的向量空间中,范数为1的向量都会分布在以原点为圆心,半径为1的圆上,如果是三维的向量空间,会分布在以原点为圆心,半径为1的圆球上。。

范数归一化与此前介绍的标准差归一化和Min-Max归一化有本质的不同,它是面向向量或矩阵的,所以默认也是按行(即向量形式)进行运算的。应用范数归一化的前提是:当前操作的多维数组是一个有意义的向量或矩阵,或者说是需要准备拿它去进行向量或矩阵运算(这在机器学习算法中很常见),在此前提下,当我们使用范数归一化时,是将一个向量(通常是二维数组中的一行)作为一个整体去运算的,通俗地说就是:此时的一行数据才是一个数(一个向量)。

“范数归一化是应用在向量(或矩阵)上”这一点也体现在了API层面上,第一点是:你可能会发现像scale()minmax_scale()这类归一化函数还可以接受一维数组,但到了normalize()就不会再接受一维数组了,需要至少要二维以上的数组(否则会报“Expected 2D array, got 1D array instead”错误),这在暗示:针对一维数组(非向量)应用范数归一化是无意义的;第二点是:像scale()minmax_scale()这类归一化函数默认是“列”向操作,而normalize()默认则是“行”向操作,这在暗示它是操作向量的,这都是根据它的实际应用场景设置的默认参数,所以能反映出它的一些本质特征。

总结一下:范数归一化是面向向量(或矩阵)的运算,所以默认也是按行(即向量形式)进行处理。

2. 示例

2.1 一个“无意义”的示例

有很多刚接触范数归一化的人会沿袭对其他归一化方法的理解来试图理解范数归一化,包括使用的测试数据也是一样的单列数据,就如同我们在本系列前面两篇文章中使用到的身高数据一样,于是,在初学者那里我们会常常看到类似下面的归一化结果以及数据分布图,我们要说的是:虽然计算上没有错误,但这种处理是没有意义的,也就不会出现在实际应用中,因为我们试图处理的数据根本不是一个有意义的向量数据,所以处理结果也是无意义的。那就让我们使用此前的身高数据看一下非向量(一维数组)到底会被处理成什么样子:

# 范数归一化 (在非向量上的无意义应用)

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import Normalizer
from sklearn.preprocessing import normalize
# author: https://laurence.blog.csdn.net/

%matplotlib inline
np.random.seed(42)
fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4, figsize=(13,5))

heights = np.random.normal(loc=170, scale=170*0.15, size=1000)
print("1. 原始数据")
print(f"heights (first 3 elements) = {heights[:3]}")

# 不同于scale()和minmax_scale()还能接受一维数组,normalize()已不接受一维数组了,至少要二维以上。
# 否则就会报错:Expected 2D array, got 1D array instead, 这暗示:范数归一化是面向向量或整个矩阵的
# 所以从API层面就作出了限制,因此我必须一开始将heights转置为二维(单列)数组
heights = heights.reshape(-1,1)
print(f"reshaped heights (first 3 elements) = {heights[:3].tolist()}")

ax1.hist(heights, bins=50)
ax1.set_title("raw data")
ax1.annotate(f"σ = {heights.std()}", (0.5, 0.95), xycoords='axes fraction', va='center', ha='center')

print("--------------------------------------------------------------------------------------------------------------")

print("2. 使用normalize按行进”行“范数归一化")
# 不指定axis参数,默认也是按行, 这也体现了normalize是面向向量运算的设计意图
normalized_heights = normalize(heights, axis=1)
print(f"normalized_heights(first 3 elements) = {normalized_heights[:3, :].tolist()}")
ax2.hist(normalized_heights, bins=50)
ax2.set_title("normalize() by row")
ax2.annotate(f"σ = {normalized_heights.std()}", (0.5, 0.95), xycoords='axes fraction', va='center', ha='center')

print("--------------------------------------------------------------------------------------------------------------")

print("3. 使用normalize按”列“进行范数归一化")
# 列向操作并不是normalize的默认操作轴向,必须显式设置!
normalized_heights = normalize(heights, axis=0)
print(f"normalized_heights(first 3 elements) = {normalized_heights[:3, :].tolist()}")
ax3.hist(normalized_heights, bins=50)
ax3.set_title("normalize() by col")
ax3.annotate(f"σ = {normalized_heights.std()}", (0.5, 0.95), xycoords='axes fraction', va='center', ha='center')

print("--------------------------------------------------------------------------------------------------------------")

print("4. 使用Normalizer进行范数归一化")
# Normalizer不可设置轴向,只能按“行”
normalized_heights = Normalizer().fit_transform(heights)
print(f"normalized_heights(first 3 elements) = {normalized_heights[:3, :].tolist()}")
ax4.hist(normalized_heights, bins=50)
ax4.set_title("Normalizer")
ax4.annotate(f"σ = {normalized_heights.std()}", (0.5, 0.95), xycoords='axes fraction', va='center', ha='center')

plt.show()

输出数据:

1. 原始数据
heights (first 3 elements) = [182.6662109  166.47426032 186.51605772]
reshaped heights (first 3 elements) = [[182.66621090178643], [166.4742603201348], [186.51605772156765]]
--------------------------------------------------------------------------------------------------------------
2. 使用normalize按行进”行“范数归一化
normalized_heights(first 3 elements) = [[1.0], [1.0], [1.0]]
--------------------------------------------------------------------------------------------------------------
3. 使用normalize按”列“进行范数归一化
normalized_heights(first 3 elements) = [[0.03352337883141376], [0.030551789884073692], [0.03422991274781404]]
--------------------------------------------------------------------------------------------------------------
4. 使用Normalizer进行范数归一化
normalized_heights(first 3 elements) = [[1.0], [1.0], [1.0]]

输出图表:

在这里插入图片描述

现在我们来解读一下程序输出的数据和图表。我们准备的身高数据并不是一个向量,在还没有认识到这个问题的情况下,为了能够进行范数归一化,我们把它强行转置为一个二维(单列)数组:

[[182.66621090178643], 
 [166.47426032013480], 
 [186.51605772156765],
 ...
 [165.84179242457762]]

在此基础上,我们有两种选择,也是看待数据的两种方式:

  • 按“行”范数归一化

如果我们打算按“行”进行范数归一化,则每一行会被视为一个向量,由于我们的数据一行只有一个元素,即一个向量只有一个分量,套用范数归一化的计算公式可知,不管是什么值,计算出的结果都为1,所以1000行数据就被转置为了:

[[1.0], 
 [1.0], 
 [1.0],
 ...
 [1.0]]

此时数据分布就变为图中第2和第4两个子图的样子,这种转换毫无意义。

  • 按“列”范数归一化

如果我们打算按“列”进行范数归一化,则每一列会被视为一个向量,此时,我们只有一个向量,这个向量包含1000个维度的分量,经归一化处理后,得到的结果是:

[[0.03352337883141376], 
 [0.030551789884073692], 
 [0.03422991274781404],
 ...
 [0.03123451354323424]]

对应的数据分布就是图3所示的样子,看上去已经“有那味”了,数据被缩放了,分布还保持与原始数据一样,很多介绍范数的文章就到此结束了。然而实际的情况是:这个由1000个身高数据组成的向量是一个“怪物”,根本不是一个有意义的向量,完全体现不出范数归一化的作用。

2.2 一个“有意义”的示例

由于我们准备的身高数据不是一组有意义的向量,这导致上面的示例不管是按行还是按列,都无法展示范数归一化的真正效果,问题的关键就是:身高数据是一个单维数据,我们需要准备至少包含两个维度的向量来演示范数归一化,才能看到它的转换效果。所以,我们应该再引入一个维度:体重,组成一个由身高和体重构成的二维向量,然后对其进行范数归一化:

# 范数归一化 (在向量上的有意义应用)

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import normalize
from sklearn.preprocessing import StandardScaler
# author: https://laurence.blog.csdn.net/

%matplotlib inline
np.random.seed(42)
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15,5))

# 我们不能再用身高数据演示范数归一化了,因为从数据的意义上讲它是一”列“数据,而范数归一化是面向向量(或矩阵)的,也就是一行数据
# 如果我们把这组身高数据当成”行“进行范数归一化,可以计算,但没有任何意义,因为这组数据不是一个向量;
# 如果我们把这组身高数据当成”列“进行范数归一化,则每一行只有一个元素,所以归一化的结果是:所有的身高数据都被缩放成了1,这也没有意义

# 使用有意义的二维向量
heights_weights = np.random.normal(loc=(170, 60), scale=(170*0.15, 60*0.15), size=(1000, 2))

print("1. 原始数据")
print(f"heights_weights (first 2 elements) = {heights_weights[:2, :].tolist()}")
ax1.scatter(x=heights_weights[:,0], y=heights_weights[:,1])
ax1.set_title("raw data")

print("-------------------------------------------------------------------------------------------------------------------------------------")

print("2. 使用normalize范数归一化")
# 默认按行向量进行范数归一化,也符合我们的期望,针对本数据按“列”无意义,不演示
normalized_heights_weights = normalize(heights_weights)
print(f"normalized_heights_weights (first 2 elements) = {normalized_heights_weights[:2, :].tolist()}")
ax2.scatter(x=normalized_heights_weights[:,0], y=normalized_heights_weights[:,1])
ax2.set_title("normalize()")

print("-------------------------------------------------------------------------------------------------------------------------------------")

print("3. 使用Normalizer范数归一化")
# 只能按行向量进行范数归一化,也符合我们的期望,针对本数据按“列”无意义,不演示
normalized_heights_weights = Normalizer().fit_transform(heights_weights)
print(f"normalized_heights_weights (first 2 elements) = {normalized_heights_weights[:2, :].tolist()}")
ax3.scatter(x=normalized_heights_weights[:,0], y=normalized_heights_weights[:,1])
ax3.set_title("Normalizer (center view)")
ax3.set(xlim=(-1, 1),ylim=(-1, 1))
ax3.axvline(x=0, c='grey')
ax3.axhline(y=0, c='grey')

plt.show()

# 调研数据分布变化

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,5))
ax1.hist(heights_weights, bins=50)
ax1.set_title("raw data")
# 经过范数归一化后,每一行元素(向量分量)除以的范数都是不一样的,所以每一列元素实际上是进行了
# 无规律的缩放,所以如果观察列数据的分布,其经过范数归一化后,分布一定改变了。但这是在用非向量
# 的视角看待数据,使用范数归一化的场景不会受此影响,也不关注这个问题。
ax2.hist(normalized_heights_weights, bins=50)
ax2.set_title("normalize data")

plt.show()

输出数据:

1. 原始数据
heights_weights (first 2 elements) = [[182.66621090178643, 58.75562128945934], [186.51605772156765, 73.70726870767223]]
-------------------------------------------------------------------------------------------------------------------------------------
2. 使用normalize范数归一化
normalized_heights_weights (first 2 elements) = [[0.9519655603640547, 0.30620511406694606], [0.9300146475620354, 0.3675224555317171]]
-------------------------------------------------------------------------------------------------------------------------------------
3. 使用Normalizer范数归一化
normalized_heights_weights (first 2 elements) = [[0.9519655603640547, 0.30620511406694606], [0.9300146475620354, 0.3675224555317171]]

输出图表:

在这里插入图片描述

改用二维向量数据后,我们能就能从图表中发现范数归一化的真正效果。左一图中的每一个点可以视为一个向量,经过范数归一化后,数据呈现出图二的分布状态,所有向量的“长度”(范数)全部变成了1,表现到图表上就是它们被缩放到了以原点为圆心,1为半径的圆上!同时,可以看到正态分布对点位在圆上的分布影响,而图三是为了凸显归一化后数据是分布在单位圆上,特意将坐标系居中显示,从中可以观察到那是单位园上的一小段圆弧。最后,我们再看一下数据分布:

在这里插入图片描述

由于数据是按行处理的,所以从列向角度看,同一个列(例如身高)中的每个元素都除以了不同的数(所在行的范数),所以列的数据分布必然会发生改变,上图显示的非常明显。但同样的道理,因为现在的场景是向量运算,所以也不会考察列向数据的分布。这就是我们在介绍范数归一化时反复强调的:范数归一化和标准差归一化、Min-Max归一化等其他归一化方法是完全不同的缩放手段,它缩放的是向量。

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

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

相关文章

博云荣获证券基金信创联盟年度优秀成员

1月12日,证券基金行业信息技术应用创新联盟(以下简称“联盟”)2022年度峰会在上海顺利举行。会上,联盟为2022年积极参与联盟工作的成员单位进行了颁奖,博云获评信创联盟年度优秀成员奖。 联盟是在中国证券监督管理委员…

Spring | SM整合(Spring+MyBatis)

0️⃣使用工具编辑器:IDEA企业版构建系统:Maven数据库:MySQL1️⃣创建项目🎏创建maven项目选择新建项目,在E盘下创建名为SMDemo的项目,构建系统选择Maven.🎏项目结构src/main/java - java 逻辑代…

企业宣传新闻稿撰写方法和技巧分享,纯干货

企业宣传新闻稿重点在于“宣传”,目的性强,具有极强的商业价值,怎么撰写是一大难关。 企业新闻稿堪比公关小组,表面上看起来只是简简单单一篇新闻稿,但是实际上企业新闻稿也能起到大作用,企业新闻稿的价值…

Python Kafka客户端性能测试比较

前言 由于工作原因使用到了 Kafka,而现有的代码并不能满足性能需求,所以需要开发高效读写 Kafka 的工具,本文是一个 Python Kafka Client 的性能测试记录,通过本次测试,可以知道选用什么第三方库的性能最高&#xff0c…

umi4+antd5兼容360安全浏览器

项目场景: umi4创建的大屏项目,部分模块使用了antd5进行开发 问题描述 开发完成后,得知客户是360安全浏览器,内核为86,测试过程中出现了样式混乱。 混乱样式有下拉内容的组件(如select、dataPicker&#…

Microsoft 365中的智能应用—翻译、朗读、听写

Microsoft 365 是一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将Word、Excel、PowerPoint和Outlook、OneNote等应用与OneDrive 和 Microsoft Teams等强大的云服务相结合,让任何人使用任何设备随时随地创建和共享内容。 Microsof…

【JavaScript】仿青柠搜索界面

点击搜索栏&#xff0c;背景模糊&#xff0c;出现图标。点击界面任意处&#xff0c;失去焦点&#xff0c;恢复原样 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X…

Elasticsearch高级查询—— 查询所有文档

目录一、初始化文档数据二、查询所有文档示例一、初始化文档数据 在 Postman 中&#xff0c;向 ES 服务器发 POST 请求 &#xff1a;http://localhost:9200/user/_doc/1&#xff0c;请求体内容为&#xff1a; {"name":"张三","age":22,"sex…

Qt的开源库TabToolbar

开源地址&#xff1a;https://github.com/SeriousAlexej/TabToolbar 该库的使用方式有两种&#xff1a; 使用json配置文件配置TabToolBar使用代码构建TabToolBar 编译 项目是使用Qt和CMake管理的&#xff0c;并且在开发的时候使用的是Qt6&#xff0c;我实测通过更改CMake的…

设计模式——代理模式

文章目录引入案例提出问题解决思路遇到的困难代理模式概念生活中的代理相关术语静态代理动态代理织入的概念基于JDK的动态代理基于Cglib的动态代理JDK 和 CGLIB 的区别引入案例 计数器的接口 public interface Calculator {int add(int i, int j);int sub(int i, int j);int …

pandas案例——预处理部分地区数据

数据清洗的任务是过滤那些不符合要求的数据&#xff0c;将过滤的结果交给业务主管部门&#xff0c;确认是否过滤掉还是由业务单位修正之后再进行抽取。不符合要求的数据主要是有不完整的数据、错误的数据、重复的数据三大类。数据清洗是与问卷审核不同&#xff0c;录入后的数据…

使用反射和泛型简化Golang查询数据库代码的方案

大纲Postgresql数组案例常规写法定义结构体查询数据问题反射泛型写法结构体定义接口Tag实现逻辑泛型设计实例化模型结构体获取表名过滤字段组装SQL语句查询遍历读取结果实例化模型结构体组装Scan方法的参数调用Scan方法并保存结果完整代码小结Postgresql数组 Postgresql有个很…

7、操作DOM对象(重点)

核心&#xff1a;浏览器网页就是一个DOM树形结构 更新&#xff1a;更新该DOM节点的内容&#xff0c;相当于更新了该DOM节点表示的HTML的内容&#xff1b; 遍历&#xff1a;遍历该DOM节点下的子节点&#xff0c;以便进行进一步操作&#xff1b; 添加&#xff1a;在该DOM节点下…

Matlab中的dsp.AudioFileReader函数的认识和学习

在Matlab中的dsp.AudioFileReader函数的认识和学习1.描述2.语法2.1 语法描述2.2 属性Properties2.3 举例Stream from audio file 来自音频文件的流 1.描述 dsp.AudioFileReader系统对象™ 从音频文件读取音频样本。 要从音频文件读取音频样本&#xff0c;请执行以下操作&…

小方制药冲刺A股上市:毛利率走低,方之光、鲁爱萍夫妇为实控人

近日&#xff0c;上海小方制药股份有限公司&#xff08;下称“小方制药”&#xff09;公开预披露更新招股书&#xff0c;准备在上海证券交易所主板上市。据贝多财经了解&#xff0c;小方制药于2022年7月1日递交招股书&#xff0c;国信证券为其保荐机构。 本次冲刺上市&#xff…

扫码器:壹码通(EMT 6621)二维码带多个回车换行处理

摘要&#xff1a;二维码运用越来越广泛了&#xff0c;目前在医院中一个二维码可以串联多个系统&#xff0c;二维码的内容也可以设置一些特殊字符去达成系统便捷性。本次遇到为二维码中开头内置了回车和空格&#xff0c;在程序判断为回车(KEY_ENTER)时就会触发业务逻辑&#xff…

mybatis之一级缓存和二级缓存

缓存&#xff1a; 查询需要连接数据库&#xff0c;非常的耗费资源&#xff0c;将一次查询的结果&#xff0c;暂存在一个可以直接取到的地方&#xff0c;我们将其称之为缓存&#xff0c;当我们需要再次查询相同的数据时&#xff0c;直接走缓存这个过程&#xff0c;就不用走数据…

【RabbitMQ三】——RabbitMQ工作队列模式(Work Queues)

RabbitMQ工作队列模式为什么要有工作队列模式如何使用工作队列模式轮询消息确认验证消息确认消息持久化公平调度验证公平调度**现在将消费者1中的Thread.sleep(1000)改为Thread.sleep(3000);不添加公平调度相关代码进行测试。**现在将消费者1中的Thread.sleep(1000)改为Thread.…

BC即将登录Coinbase Institutional,2023年以全新姿态出发

以支付为最初定位的加密资产&#xff0c;在支付领域的发展始终停滞不前&#xff0c;尤其是在2022年&#xff0c;加密行业经历了几次“至暗时刻”&#xff0c;导致加密市场资金不断出逃市场全面转熊&#xff0c;越来越多的人对加密资产市场的发展前景失去信心。 而在2021年年底开…

【GD32F427开发板试用】移植CoreMark验证0等待区Flash大小

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;Doravmon 引言 非常荣幸能够参与到此次GD32F427开发板试用的活动中来&#xff0c;在拿到开发板之前就翻了翻手册&#xff0c;一直有个疑问困惑…