Skip to content

Commit

Permalink
update ndarray view
Browse files Browse the repository at this point in the history
  • Loading branch information
llinjupt committed May 9, 2019
1 parent 886504f commit e60b4ee
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
Binary file added imgs/numpy/ndarray.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
102 changes: 98 additions & 4 deletions numpy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ ndarray(n dimention array,多维数组)对象是 NumPy 的数据承载核
- 转换数组类型不可以直接更改 dtype,它用于对数据存储区域的解读方式,例如 float64 对应 8 个 bytes,int32 对应 4 个 bytes,直接更改 dtype 会让 float64 类型的数组元素个数翻倍,并未实际改变数组类型。正确的方法应该通过 np.astype 方法进行。
- 更新数组元素时,会强制把新元素的数据类型转换为数组的 dtype。

.. figure:: imgs/numpy/ndarray.png
:scale: 70%
:align: center
:alt: borders

ndarray 结构 (图自 Enthought, Inc.)

不同维度的数组
~~~~~~~~~~~~~~

Expand Down Expand Up @@ -293,15 +300,102 @@ np.array 会根据提供的数据自动选择 int32 或 flot64 作为数组的 d
int32
[0 0]
数组视窗
数组视图
~~~~~~~~~~~~
NumPy 中提供了大量的对数组进行处理的函数,这些函数返回的新数组中的元素和原数组元素具有两种关系:
- 引用,也即不对原数组中元素复制,修改元素会相互影响。
- 复制,拷贝副本,修改不会互相影响。包含简单索引(例如简单索引和切片组合使用)的引用方式,均会进行复制。
一个数组被称为数组包含的数据的一个视窗,所以如果是引用返回的数组,则称为数据的另一个视窗。不同视窗是对数据的不同观察方式,体现在数组上就是形式的变形,不会拷贝任何东西。视窗也被称为视图(view)。
一个数组被称为数组包含的数据的一个视图(view),所以如果是引用返回的数组,则称为数据的另一个视图。不同视窗是对数据的不同观察方式,体现在数组上就是形式的变形,不会拷贝任何东西。视图也被称为视窗。
步长 strides 是另一个 ndarray 对象成员,它对于理解数组视图至关重要。
.. code-block:: python
:linenos:
:lineno-start: 0
x = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.int8)
t = x.T
print(id(x.data), id(t.data))
>>>
1621569473776 1621569473776
转置不会复制数据,所以 t 和 x 的 data 地址是相同的。但是它们的 stides 是不同的:
.. code-block:: python
:linenos:
:lineno-start: 0
print(x.strides)
>>>
(3, 1)
print(t.strides)
>>>
(1, 3)
strides 是一个元组,它的元素个数与 shape 元素个数相同,它记录了查找对应轴下一个元素需要偏移的字节数。为了加速访问数据,ndarray 对象的 data 数据在内存中均是连续成块存储的,所以如何解读这一块数据,就需要 strides 来指示。
这里的 x 类型定义为 int8,所以每个元素占用 1 个字节,x 的 strides 为 (3, 1) 表示:
- 需要偏移 3 个字节找到下一行的开始数据。
- 需要偏移 1 个字节找到下一列的开始数据。
有了 shape 和 strides 就构成了一个视图,可以对元素进行不同的行列解读。
在大部分创建数组对象的函数中接受 order 参数,用于指定行优先或者列优先,例如:
- ‘C’ 表示行优先(row major),numpy 的默认参数。
- ‘F’ 表示列优先(column major),Fortran 语言默认使用列优先。
不同的 order 创建的数组的 strides 是不同的,例如:
.. code-block:: python
:linenos:
:lineno-start: 0
y = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.int8, order='F')
print(y.strides)
>>>
(1, 3)
如果数组元素索引为 i[0], i[1], ..., i[n],通过 strides 可以计算出元素在数组中的偏移字节数:
.. code-block:: python
:linenos:
:lineno-start: 0
offset = sum(np.array(i) * a.strides)
下面的示例构造一个从 0 开始的,差为 1 的等差数列,这样保证元素的偏移 = 数组元素 * itemsize:
.. code-block:: python
:linenos:
:lineno-start: 0
In [0]: x = np.reshape(np.arange(5*6*7*8), (5,6,7,8)).transpose(2,3,1,0)
In [1]: x.strides
Out[1]: (32, 4, 224, 1344)
# 计算[3,5,2,2]索引处的元素偏移字节数
In [2]: offset = sum(np.array([3,5,2,2]) * x.strides)
In [3]: x[3,5,2,2]
Out[3]: 813
In [4]: offset / x.itemsize
Out[4]: 813.0
创建数组
------------
Expand Down Expand Up @@ -4077,7 +4171,7 @@ NumPy 的广播遵循一组严格的规则,设定这组规则是为了决定
1. 规则1,如果两个数组的维度(ndim,轴数)不相同,那么小轴数的数组形状在最左边补 1 以使得维度(轴数)相同。
#. 规则2,如果两个数组的形状在各轴的维数(元素数)不匹配, 那么数组的形状会沿着元素个数为 1 的轴扩展以匹配另外一个数组的形状。
#. 规则3,扩展后两个数组的形状不匹配并且任何一个数组都没再有维度为 1 的轴, 报错处理,否则继续规则 2。
#. 规则3,扩展后两个数组的形状不匹配并且任何一个数组都不再有维度为 1 的轴, 报错处理,否则继续规则 2。
来看两个数组均需要广播的示例:
Expand Down Expand Up @@ -4857,7 +4951,7 @@ A[0,1],A[1,0] 和 A[1,1] 对应元素均大于 0。A[B] 等价于 A[np.where(A
>>>
[0 3] # 对应 [A[0,0] A[1,1]]
使用列表作为索引的结果均是一维数组。
每个维度上的索引列表长度必须一致,以进行行列的索引配对,使用列表作为索引的结果均是一维数组。
索引数组
``````````
Expand Down

0 comments on commit e60b4ee

Please sign in to comment.