超详细的图解 Numpy,不收藏后悔!_numpy、-程序员宅基地

技术标签: python  机器学习  人工智能  numpy  

Numpy是关于机器学习,数据处理的Python基础库,了解 NumPy 的工作原理可以提高你的编码效率,可以让你的代码看上去更加简洁和优雅。 NumPy 也可以GPU上运行代码而无需更改原始代码(或只做少量更改)。

NumPy 的核心概念是 多维数组。它的美妙之处在于,无论数组有多少维,大多数操作看起来都是一样的。但是 1D 和 2D 的情况有点特殊。文章由三部分组成:

  1. 向量,一维数组
  2. 矩阵,二维数组
  3. 3D及以上

Numpy 数组与 Python 列表(list)

粗看上去,NumPy 数组类似于 Python 列表。它们都用作容器,具有快速的原始获取和设置以及元素的插入和删除速度稍慢。

先看一个最简单的例子,Numpy能打败Python的list主要体现在算术计算上:

 除此之外,NumPy 数组的优缺点主要体现在:

  • Numpy更紧凑,尤其是当有多个维度时。
  • Numpy的向量化操作List表更快。
  • Numpy将元素附加到末尾时比List慢。
  • Numpy和List共同特点是:只能快速处理一种类型的元素。

 这里的大O表示运算的时间复杂度, O(N)表示运算的时间与数组的大小成正比。O*(1)表运算示时间一般不依赖于数组的大小。

1.向量,一维数组

向量初始化

创建 NumPy 数组的一种方法是通过将python的list 转换成numpy的数组:

NumPy 数组不能像 Python list 那样很方便的进行扩展(append):因为它在数组末尾没有保留空间以方便快速扩展。因此,通常的做法是先扩展 Python 列表然后将其转换为 NumPy 数组,或者使用 np.zerosnp.empty  预先分配必要的空间。

通常我们需要创建一个空数组来匹配现有数组的形状和元素类型 :

实际上,所有创建一个填充常量值的数组的函数都有_like对应的函数:

 NumPy 中创建序列数组初始化的函数有两个:

如果您需要一个外观相似的浮点数数组,例如[0., 1., 2.],您可以更改arange输出的类型:arange(3).astype(float),但还有更好的方法,由于arange函数是类型敏感的:如果您输入整数作为参数,它将生成整数,如果您输入浮点数(例如arange(3.)),它将生成浮点数。 

但arange不是特别擅长处理浮点数:

 np.arange(start,stop,step)通常情况下比较擅长处理整数,也可以处理浮动数,但是处理浮动数时可读性较差,因为当参数start,stop,step的小数位数不一致时,生产的结果有时难以理解(比如上图中的solution1的结果),因为浮点数没有连续的概念。 当需要生成浮点数序列数组时更为有效的方法是使用np.linspace(start,stop,num)方法,其中num必须是整数,np.linspace生成的浮点数序列并不是连续的,它只是在start,stop之间均匀的生成num个浮点数(包含start,stop在内)。即x∈[start,stop]。但是有一些numpy生产的浮动数序列并不是闭区间的,比如用numpy生成随机数序列:

在Numpy中还有一个用于生成随机数组的新接口。它的特点是:

  • 更适合多线程
  • 速度更快
  • 更可配置(您可以通过选择非默认的所谓“位生成器”来获得更快的速度或更高的质量) 

向量索引

当将数据放入数组后,NumPy 非常擅长提供简单的方法来返回部分或全部的结果:

 上面介绍的多种通过多种花哨的索引来裁剪数组的方法,但是它们的结果实际上都是所谓的“视图(view)”:如果数据在被索引后发生变化,它们不会存储数据并反映原始数组中的变(赋值操作除外)。下面是对list和numpy数组进行切片和赋值后的结果差异的对比:

 从 NumPy 数组获取数据的另一种非常有用的方法是布尔索引,它允许使用各种逻辑运算符:

 numpy数组通过使用布尔索引的方式也可以对原数组进行赋值。为此衍生出来的两个常用的方法:np.where和np.clip

 请注意,np.where使用一个参数返回一个数组元组(1D 情况下为 1 元组,2D 情况下为 2 元组等),因此您需要在上面的示例中写入np.where(a>5)[0]这种方式来返回你想要的数组。

向量运算

向量化运算的速度是 Numpy最值得夸耀的地方。向量化运算达到了 c++ 运算的级别,使我们能够避免缓慢的 Python 循环的成本。NumPy 允许像普通数字一样操作整个数组:

 和 Python 中一样,a//b 表示 整除(得到商),x**n 表示 xⁿ

当一个数组与一个数做加减乘除时,表示数组的每个元素都与这个数做相关的运算。(也称为广播):

大多数数学函数都有NumPy函数与之对应:

 在numpy中向量的点积与叉积有自己运算符:

 在numpy中也有三角函数运算符:

 在numpy中还有多种不同的取整函数:

 这里np.floor是向下取整,np.ceil是向上取整,而np.round 并非是“四舍五入”,而是“去奇存偶”,或者说 “4舍6入5凑偶”,与一般理解的四舍五入不同:当整数部分是偶数,小数部分是0.5时,向下取整,最后结果为偶数。当整数部分是奇数,小数部分是0.5时,则向上取整,最后结果为偶数。这样得到的结果在统计学上更精确。numpy的round函数采用的是这种方法。

numpy还有一些基本的统计函数:

这些函数中的每一个都有一个 nan-resistant 变体:例如nansumnanmax

从上面的公式可以看出,在总体均值未知时从样本估计 std 的最典型用例中,std和都var忽略贝塞尔校正并给出有偏差的结果。获得较少偏差估计的标准方法是n-1在分母中使用ddof=1('delta degrees of freedom'):

Pandas std默认使用贝塞尔校正 

随着样本量的增加,贝塞尔校正的效果会迅速减弱。此外,它不是一个标准的通用解决方案,例如正态分布ddof=1.5 更好: 

 排序函数的功能少于 Python  对应函数:

 在一维情况下,reversed可以通过反转结果轻松补偿关键字的缺失。在 2D 中,它有点困难

在向量中搜索元素

与Python的List不同,NumPy 数组没有index方法。 所以查找元素是Numpy的一个痛点:

  • 一种查找元素的方法是np.where(a==x)[0][0],但它效率不高,因为它需要遍历数组的所有元素,即使要查找的元素在最开始位置。
  • 另一种更快的方法是使用 Numba 加速 next((i[0] for i, v in np.ndenumerate(a) if v==x), -1) (否则在最坏的情况下比 where 还要慢).
  • 一旦对数组进行排序,情况就会好转:v = np.searchsorted(a, x); return v if a[v]==x else -1 确实很快,复杂度为 O(log N),但首先需要 O(N log N) 时间进行排序。

浮点运算比较 

函数np.allclose(a, b)用于比较具有给定公差的浮点数组:

  • np.allclose假设所有的比较数字的等级是1个单位。例如在上图中,它就认为1e-9和2e-9相同,如果要进行更细致的比较,需要通过atol指定比较等级1:np.allclose(1e-9, 2e-9, atol=1e-17) == False。
  • math.isclose进行比较没有假设前提,而是基于用户给出的一个合理abs_tol值:math.isclose(0.1+0.2–0.3, abs_tol=1e-8) == True。

除此之外np.allclose在绝对和相对公差公式中还存在一些小问题,例如,对某些数存在allclose(a, b) != allclose(b, a)。这些问题已在math.isclose函数中得到解决。

2.矩阵,二维数组

NumPy 中曾经有一个专门的matrix类,但现在已弃用,因此我将交替使用矩阵和二维数组这两个词。

矩阵初始化语法类似于向量:

这里需要双括号,因为第二个位置参数是为(可选)dtype(也接受整数)保留的。

随机矩阵生成也类似于向量:

 还有一种更简洁的随机数生成方式:

 二维索引语法比嵌套列表更方便:

 和一维数组一样,上图的view表示,切片数组实际上并未进行任何复制。修改数组后,更改也将反映在切片中。

axis参数 

在许多操作(例如求和)中,我们需要告诉NumPy是否要跨行或跨列进行操作。为了使用任意维数的通用表示法,NumPy引入了axis的概念:axis参数实际上是所讨论索引的数量:第一个索引是axis=0,第二个索引是axis=1,等等。

因此在二维数组中,如果axis=0是按列,那么axis=1就是按行。

矩阵运算

除了按元素工作的普通运算符(如 +、-、*、/、// 和 **)之外,还有一个计算矩阵乘积的 @ 运算符: 

 

 在第一部分中,我们已经看到向量乘积的运算,NumPy允许向量和矩阵之间,甚至两个向量之间进行元素的混合运算:

请注意,在最后一个示例中,它是一个对称的每元素乘法(笛卡尔积)。要使用非对称线性代数矩阵乘法计算外积,应颠倒操作数的顺序:

从上面的示例可以看出,在二维数组中,行向量和列向量被不同地对待。

默认情况下,一维数组在二维操作中被视为行向量。因此,将矩阵乘以行向量时,可以使用(n,)或(1,n),结果将相同。

如果需要列向量,则有转置方法对其进行操作:

 能够从一维数组中生成二位数组列向量的两个操作是使用命令reshape重排和newaxis建立新索引:

这里的-1参数表示reshape自动计算第二个维度上的数组长度,None在方括号中充当np.newaxis的快捷方式,该快捷方式在指定位置添加了一个空axis。

因此,NumPy中总共有三种类型的向量:一维数组,二维行向量和二维列向量。这是两者之间显式转换的示意图:

flatten始终是一个副本,reshape (-1) 始终是一个视图,ravel尽可能是一个视图 

根据规则,一维数组被隐式解释为二维行向量,因此通常不必在这两个数组之间进行转换,相应区域用灰色标出。 

矩阵操作

连接矩阵有两个主要函数:

这两个函数只堆叠矩阵或只堆叠向量时,都可以正常工作。但是当涉及一维数组与矩阵之间的混合堆叠时,vstack可以正常工作:hstack会出现尺寸不匹配错误。

因为如上所述,一维数组被解释为行向量,而不是列向量。解决方法是将其转换为列向量,或者使用column_stack自动执行:

 堆叠的逆向操作是拆分:

 所有split风格都接受要拆分的索引列表作为参数,或单个整数作为参数,即大小相等的部分的数量:

 

 矩阵可以通过两种方式完成复制:tile类似于复制粘贴,repeat类似于分页打印。

特定的列和行可以用delete进行删除:

逆运算是插入(insert)

 append就像hstack一样,该函数无法自动转置一维数组,因此再次需要对向量进行转置或添加长度,或者使用column_stack代替:

 实际上,如果您需要做的只是将常量值添加到数组的边界,那么(稍微有点复杂)pad 函数就足够了:

Meshgrids

广播规会让使用 meshgrids 变得更简单。假设,您需要以下矩阵(但尺寸非常大):

两种明显的方法都很慢,因为它们使用 Python 循环。处理此类问题的MATLAB的方法是创建一个meshgrid:

meshgrid函数接受任意一组索引,该mgrid只是切片并且,indices只能生成完整的索引范围。fromfunction如上所述,使用 I 和 J 参数调用提供的函数一次。

但实际上,在 NumPy 中有更好的方法。没有必要在整个 I 和 J 矩阵上花费内存(即使meshgrid足够聪明,如果可能的话只存储对原始向量的引用)。只存储正确形状的向量就足够了,其余的由广播规则处理:

如果没有indexing=’ij’参数,meshgrid将更改参数的顺序:J, I= np.meshgrid(j, i)—它是一种“xy”模式,可用于可视化 3D 绘图(请参阅文档中的示例)。

除了在二维或三维网格上初始化函数外,网格对于索引数组也很有用:

 

也适用于稀疏网格 

矩阵统计

就像 一样sum函数,所有其他统计函数 (min/maxargmin/argmaxmean/median/percentilestd/var)接受 axis 参数并相应地执行操作:

在二维及更高版本中的argminandargmax函数有返回扁平化索引(最小值和最大值的第一个实例)的麻烦。要将其转换为两个坐标,unravel_index需要一个函数 :

all和any两个函数也能使用axis参数:

矩阵排序

尽管axis参数对上面列出的函数有帮助,但对 二维 排序没有帮助

这通常不是您希望对矩阵或电子表格进行排序的结果:axis它根本不是key参数的替代品。但幸运的是,NumPy 有几个辅助函数,允许按列排序——如果需要,也可以按多列排序: 

1. a[a[:,0].argsort()] 按第一列对数组排序:

这里argsort返回排序后原始数组的索引数组。

可以重复这个技巧,但必须注意下一次排序不会弄乱上一次的结果:
a = a[a[:,2].argsort()]
a = a[a[:,1].argsort(kind='stable')]
a = a[a[:,0].argsort(kind='stable')]

 

 2. 有一个辅助函数lexsort可以按照上面描述的方式对所有可用列进行排序,但它总是按行执行,并且要排序的行的顺序是倒置的(即从下到上)所以它的用法有点麻烦,例如:
a[np.lexsort(np.rot90(a))]按从左到右的顺序按所有列排序。

 –a[np.lexsort(np.rot90(a[:,[2,5]]))]首先按第 2 列排序,然后(第 2 列中的值相等)按第 5 列排序。另一种形式是a[np.lexsort(np.flipud(a.T[[2,5]]))]

 这里 flipud 在上下方向上翻转矩阵(准确地说,在axis=0方向上,与 相同a[::-1,...],其中三个点表示“所有其他维度”——所以突然flipud,而不是fliplr,翻转一维数组)并rot90旋转矩阵在正方向(即逆时针)旋转 90 度。flips 和 rot90 都返回视图。

3. 要使用 的order参数sort,首先将数组转换为结构化形式,然后对其进行排序,最后将其转换回普通(“非结构化”)形式:

 

 这两种转换实际上都是视图,因此它们速度很快并且不需要任何额外的内存。但是功能u2ss2u需要首先导入:

from numpy.lib.recfunctions
import unstructured_to_structured as u2s, structured_to_unstructured as s2u

4. 在 Pandas 中执行此操作可能是更好的选择,因为此特定操作在那里更具可读性且更不容易出错:

  • pd.DataFrame(a).sort_values(by=[2,5]).to_numpy():先按第 2 列排序,然后按第 5 列排序。 
  • pd.DataFrame(a).sort_values().to_numpy():按从左到右的顺序对所有列排序。

3. 3维及更高维

通过重排一维向量或转换嵌套的Python列表来创建3维数组时,索引的含义为(z,y,x)。第一个索引是平面的编号,然后是该平面中的坐标:

但是此索引顺序不是通用的。处理RGB图像时,通常使用(y,x,z)顺序:前两个是像素坐标,最后一个是颜色坐标(Matplotlib中是RGB ,OpenCV中是BGR ):

RGB图像 

 这样,可以方便地引用特定像素:a[i,j]给出像素的RGB元组(i,j)。

因此,创建特定几何形状的实际命令取决于您正在处理的领域的约定:

显然,像 hstackvstack、dstack 这样的 NumPy 函数并不知道这些约定。其中硬编码的索引顺序是 (y,x,z),RGB 图像顺序: 

 堆叠RGB图像(这里只有两种颜色)

如果您的数据布局不同,使用concatenate命令堆叠图像,在参数中为其提供显式索引号axis会更方便:

如果您不方便用数轴(axis)来思考问题,可以将数组转换硬编码为hstack的形式:

 这种转换没有发生实际的复制操作。它只是混合索引的顺序。

另一个混合索引顺序的操作是数组转置。检查它可能会让您对 3维数组更加熟悉。根据您决定的轴(axis)顺序,转置数组所有平面的实际命令将有所不同:对于通用数组,它交换索引 1 和 2,对于RGB图像,它交换0和1:

 有趣的是,默认transpose的轴参数axes(以及唯一的a.T操作模式)颠倒了索引顺序,这与上面描述的索引顺序约定都不一致。

广播也适用于更高维度,有关详细信息,请参阅我的简短文章“ NumPy 中的广播”。

最后,这里有一个函数可以在处理多维数组时为您节省大量的Python 循环,并可以使您的代码更简洁 — einsum(爱因斯坦求和):

 它沿着重复索引对数组求和。在这个特定的例子中 np.tensordot(a, b, axis=1),这两种情况都足够了,但在更复杂的情况下 einsum 可能会工作得更快,而且通常更容易编写和阅读——一旦你理解了它背后的逻辑。

如果您想测试您的 NumPy 技能,GitHub 上有一套棘手的众包100 个 NumPy 练习¹⁰。

参考

  1. Scott Sievert,NumPy GPU 加速
  2. Jay Alammar,NumPy 和数据表示的可视化介绍
  3. Big-O备忘单网站
  4. Python 时间复杂度维基页面
  5. NumPy Issue #14989,排序函数中的反向参数
  6. NumPy Issue #2269,第一个非零元素
  7. Numba 图书馆主页
  8. 浮点指南,比较
  9. NumPy Issue #10161,numpy.isclose 与 math.isclose
  10. GitHub 上的 100 个 NumPy 练习

本文来自于Medium的一篇国外博主的博客文章 作者:Lev Maximov

原文地址:https://betterprogramming.pub/numpy-illustrated-the-visual-guide-to-numpy-3b1d4976de1d

\

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42608414/article/details/128774964

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan