关键词:
系列文章地址
ndarray 对象的内部机理
在前面的内容中,我们已经详细讲述了 ndarray
的使用,在本章的开始部分,我们来聊一聊 ndarray
的内部机理,以便更好的理解后续的内容。
1、ndarray 的组成
ndarray 与数组不同,它不仅仅包含数据信息,还包括其他描述信息。ndarray 内部由以下内容组成:
- 数据指针:一个指向实际数据的指针。
- 数据类型(dtype):描述了每个元素所占字节数。
- 维度(shape):一个表示数组形状的元组。
- 跨度(strides):一个表示从当前维度前进道下一维度的当前位置所需要“跨过”的字节数。
NumPy 中,数据存储在一个均匀连续的内存块中,可以这么理解,NumPy 将多维数组在内部以一维数组的方式存储,我们只要知道了每个元素所占的字节数(dtype)以及每个维度中元素的个数(shape),就可以快速定位到任意维度的任意一个元素。
dtype 及 shape 前文中已经有详细描述,这里我们来讲下 strides。
示例
ls = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]
a = np.array(ls, dtype=int)
print(a)
print(a.strides)
输出:
[[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
[[13 14 15 16]
[17 18 19 20]
[21 22 23 24]]]
(48, 16, 4)
上例中,我们定义了一个三维数组,dtype 为 int,int 占 4个字节。
第一维度,从元素 1 到元素 13,间隔 12 个元素,总字节数为 48;
第二维度,从元素 1 到元素 5,间隔 4 个元素,总字节数为 16;
第三维度,从元素 1 到元素 2,间隔 1 个元素,总字节数为 4。
所以跨度为(48, 16, 4)。
普通迭代
ndarray 的普通迭代跟 Python 及其他语言中的迭代方式无异,N 维数组,就要用 N 层的 for
循环。
示例:
import numpy as np
ls = [[1, 2], [3, 4], [5, 6]]
a = np.array(ls, dtype=int)
for row in a:
for cell in row:
print(cell)
输出:
1
2
3
4
5
6
上例中,row
的数据类型依然是 numpy.ndarray
,而 cell
的数据类型是 numpy.int32
。
nditer 多维迭代器
NumPy 提供了一个高效的多维迭代器对象:nditer 用于迭代数组。在普通方式的迭代中,N 维数组,就要用 N 层的 for
循环。但是使用 nditer
迭代器,一个 for
循环就能遍历整个数组。(因为 ndarray 在内存中是连续的,连续内存不就相当于是一维数组吗?遍历一维数组当然只需要一个 for
循环就行了。)
1、基本示例
例一:
ls = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]
a = np.array(ls, dtype=int)
for x in np.nditer(a):
print(x, end=", ")
输出:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
2、order 参数:指定访问元素的顺序
创建 ndarray 数组时,可以通过 order 参数指定元素的顺序,按行还是按列,这是什么意思呢?来看下面的示例:
例二:
ls = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]
a = np.array(ls, dtype=int, order=‘F‘)
for x in np.nditer(a):
print(x, end=", ")
输出:
1, 13, 5, 17, 9, 21, 2, 14, 6, 18, 10, 22, 3, 15, 7, 19, 11, 23, 4, 16, 8, 20, 12, 24,
nditer
默认以内存中元素的顺序(order=‘K‘)访问元素,对比例一可见,创建 ndarray 时,指定不同的顺序将影响元素在内存中的位置。
例三:nditer
也可以指定使用某种顺序遍历。
ls = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]
a = np.array(ls, dtype=int, order=‘F‘)
for x in np.nditer(a, order=‘C‘):
print(x, end=", ")
输出:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
行主顺序(
order=‘C‘
)和列主顺序(order=‘F‘
),参看 https://en.wikipedia.org/wiki/Row-_and_column-major_order。例一是行主顺序,例二是列主顺序,如果将 ndarray 数组想象成一棵树,那么会发现,行主顺序就是深度优先,而列主顺序就是广度优先。NumPy 中之所以要分行主顺序和列主顺序,主要是为了在矩阵运算中提高性能,顺序访问比非顺序访问快几个数量级。(矩阵运算将会在后面的章节中讲到)
3、op_flags 参数:迭代时修改元素的值
默认情况下,nditer 将视待迭代遍历的数组为只读对象(readonly),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 op_flags
参数为 readwrite 或者 writeonly 的模式。
例四:
import numpy as np
a = np.arange(5)
for x in np.nditer(a, op_flags=[‘readwrite‘]):
x[...] = 2 * x
print(a)
输出:
[0 1 2 3 4]
4、flags 参数
flags
参数需要传入一个数组或元组,既然参数类型是数组,我原本以为可以传入多个值的,但是,就下面介绍的 4 种常用选项,我试了,不能传多个,例如 flags=[‘f_index‘, ‘external_loop‘]
,运行报错。
(1)使用外部循环:external_loop
将一维的最内层的循环转移到外部循环迭代器,使得 NumPy 的矢量化操作在处理更大规模数据时变得更有效率。
简单来说,当指定 flags=[‘external_loop‘]
时,将返回一维数组而并非单个元素。具体来说,当 ndarray 的顺序和遍历的顺序一致时,将所有元素组成一个一维数组返回;当 ndarray 的顺序和遍历的顺序不一致时,返回每次遍历的一维数组(这句话特别不好描述,看例子就清楚了)。
例五:
import numpy as np
ls = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]
a = np.array(ls, dtype=int, order=‘C‘)
for x in np.nditer(a, flags=[‘external_loop‘], order=‘C‘):
print(x,)
输出:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]
例六:
b = np.array(ls, dtype=int, order=‘F‘)
for x in np.nditer(b, flags=[‘external_loop‘], order=‘C‘):
print(x,)
输出:
[1 2 3 4]
[5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]
[17 18 19 20]
[21 22 23 24]
(2)追踪索引:c_index、f_index、multi_index
例七:
import numpy as np
a = np.arange(6).reshape(2, 3)
it = np.nditer(a, flags=[‘f_index‘])
while not it.finished:
print("%d <%d>" % (it[0], it.index))
it.iternext()
输出:
0 <0>
1 <2>
2 <4>
3 <1>
4 <3>
5 <5>
这里索引之所以是这样的顺序,因为我们选择的是列索引(f_index)。直观的感受看下图:
遍历元素的顺序是由
order
参数决定的,而行索引(c_index)和列索引(f_index)不论如何指定,并不会影响元素返回的顺序。它们仅表示在当前内存顺序下,如果按行/列顺序返回,各个元素的下标应该是多少。
例八:
import numpy as np
a = np.arange(6).reshape(2, 3)
it = np.nditer(a, flags=[‘multi_index‘])
while not it.finished:
print("%d <%s>" % (it[0], it.multi_index))
it.iternext()
输出:
0 <(0, 0)>
1 <(0, 1)>
2 <(0, 2)>
3 <(1, 0)>
4 <(1, 1)>
5 <(1, 2)>
5、同时迭代多个数组
说到同时遍历多个数组,第一反应会想到 zip 函数,而在 nditer 中不需要。
例九:
a = np.array([1, 2, 3], dtype=int, order=‘C‘)
b = np.array([11, 12, 13], dtype=int, order=‘C‘)
for x, y in np.nditer([a, b]):
print(x, y)
输出:
1 11
2 12
3 13
其他函数
1、flatten函数
flatten
函数将多维 ndarray 展开成一维 ndarray 返回。
语法:
flatten(order=‘C‘)
示例:
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=int, order=‘C‘)
b = a.flatten()
print(b)
print(type(b))
输出:
[1 2 3 4 5 6]
<class ‘numpy.ndarray‘>
2、flat
flat
返回一个迭代器,可以遍历数组中的每一个元素。
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=int, order=‘C‘)
for b in a.flat:
print(b)
print(type(a.flat))
输出:
1
2
3
4
5
6
<class ‘numpy.flatiter‘>
回炉重造python之numpy详细教程(2万字总结)(代码片段)
Python之numpy详细教程前言安装:Numpy库介绍安装:教程地址:Numpy数组和Python列表性能对比:NumPy数组基本用法numpy中的数组:创建数组(np.ndarray对象):ndarray常用属性:`ndarray.dtype` 查看详情
附录anumpy高级应用(代码片段)
在这篇附录中,我会深入NumPy库的数组计算。这会包括ndarray更内部的细节,和更高级的数组操作和算法。本章包括了一些杂乱的章节,不需要仔细研究。A.1ndarray对象的内部机理NumPy的ndarray提供了一种将同质数据块(可以是连续... 查看详情
numpy基础教程之numpy的介绍
...重要的基础包之一,大多数提供科学计算的包都以Numpy的ndarray(多维数组)为构建基础。下面我们就通过一些实例来初步了解下ndarray,要想使用ndarray,需要导入numpy库。ndarray的创建非常简单,只需要将列表传入到array()函数即可... 查看详情
numpy基础教程之numpy的介绍
...重要的基础包之一,大多数提供科学计算的包都以Numpy的ndarray(多维数组)为构建基础。下面我们就通过一些实例来初步了解下ndarray,要想使用ndarray,需要导入numpy库。ndarray的创建非常简单,只需要将列表传入到array()函数即可... 查看详情
一文带你斩杀python之numpy☀️pandas全部操作全网最详细❗❗❗(代码片段)
...的表示1.3三维数据的表示2、为什么要使用Numpy2.1、Numpy的ndarray具有广播功能2.2Numpy数组的性能比Python原生数据类型高3ndarray的属性和基本操作3.1ndarray的基本属性 3.2ndarray元素类型 3.3创建ndarray的方式3.4ndarray对象的变换 查看详情
超详细pytorch入门教程(代码片段)
Pytorch基本语法1认识Pytorch2Pytorch的基本元素操作3Pytorch的基本运算操作4关于TorchTensor和Numpyarray之间的相互转换5总结1认识Pytorch什么是Pytorch?Pytorch是一个基于Numpy的科学计算包,向它的使用者提供了两大功能.作为Numpy的替代者,... 查看详情
TypeError: 不支持的操作数类型 -: 'numpy.ndarray' 和 'numpy.ndarray'
】TypeError:不支持的操作数类型-:\\\'numpy.ndarray\\\'和\\\'numpy.ndarray\\\'【英文标题】:TypeError:unsupportedoperandtype(s)for-:\'numpy.ndarray\'and\'numpy.ndarray\'TypeError:不支持的操作数类型-:\'numpy.ndarray\'和\'numpy.ndarray\'【发布时间】:2013-04- 查看详情
超简单!pytorch入门教程:autograd
一、autograd自动微分autograd是专门为了BP算法设计的,所以这autograd只对输出值为标量的有用,因为损失函数的输出是一个标量。如果y是一个向量,那么backward()函数就会失效。不知道BP算法是什么的同学,估计也不知道什么是深度... 查看详情
numpy和matplotlib的简单应用(代码片段)
...1.numpy库 NumPy(NumericPython)提供了一个N维的数组类型ndarray,Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,效率远高于纯Python代码。 ndarray到底跟原生python列表的... 查看详情
hadoop核心架构hdfs+mapreduce+hbase+hive内部机理详解
...sp; 通过这一阶段的调研总结,从内部机理的角度详细分析,HDFS、MapReduce、Hbase、Hive是如何运行,以及基于Ha 查看详情
numpy与matplotlib的应用(代码片段)
...1.numpy库 NumPy(NumericPython)提供了一个N维的数组类型ndarray,Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,效率远高于纯Python代码。 ndarray到底跟原生python列表的... 查看详情
numpy的详细教程
NumPy的详细教程转载http://blog.csdn.net/chen_shiqiang/article/details/51868115先决条件在阅读这个教程之前,你多少需要知道点python。如果你想从新回忆下,请看看 PythonTutorial .如果你想要运行教程中的示例,你至少需要在你的电脑... 查看详情
numpy-1
NumPy数组NumPy数组是一个多维数组对象,称为ndarray。其由两部分组成:实际的数据描述这些数据的元数据大部分操作仅针对于元数据,而不改变底层实际的数据。关于NumPy数组有几点必需了解的:NumPy数组的下标从0开始。同一个Nu... 查看详情
python数据分析与展示numpy入门(代码片段)
...Numpy入门一、Numpy基础1.1NumPy简介1.2NumPy的引用及输出二、ndarray对象2.1ndarray对象的属性2.2ndarray数组的元素类型三、ndarray操作3.1ndarray数组的创建3.2ndarray数组的变换3.3ndarray数组的索引和切片3.4ndarray数组的运算四、Numpy的数据存取4.1... 查看详情
numpy.ndarray 稀疏矩阵到密集
】numpy.ndarray稀疏矩阵到密集【英文标题】:numpy.ndarraysparsematrixtodense【发布时间】:2019-09-0209:14:08【问题描述】:我想对一些打包为numpy.ndarray的数据运行sklearn的RandomForestClassifier,而这些数据恰好是稀疏的。调用fit会得到ValueErro... 查看详情
如何使用 ctypes 将 numpy ndarrays 传递给 c++ 函数?
】如何使用ctypes将numpyndarrays传递给c++函数?【英文标题】:Howtopassnumpyndarraystoac++functionusingctypes?【发布时间】:2019-09-1520:26:08【问题描述】:我花了两天时间弄清楚如何将ndarrays传递给c/c++,但仍然没有找到任何可以正常工作的... 查看详情
numpy.ndarray 的类型提示/注释 (PEP 484)
】numpy.ndarray的类型提示/注释(PEP484)【英文标题】:Typehinting/annotation(PEP484)fornumpy.ndarray【发布时间】:2016-06-1023:27:52【问题描述】:是否有人为特定的numpy.ndarray类实现了类型提示?现在,我使用的是typing.Any,但如果有更具体的... 查看详情
numpy学习心得
NumPy数组NumPy数组是一个多维数组对象,称为ndarray。其由两部分组成:实际的数据描述这些数据的元数据大部分操作仅针对于元数据,而不改变底层实际的数据。关于NumPy数组有几点必需了解的:NumPy数组的下标从0开始。同一个Nu... 查看详情