深入理解NumPy简明教程---数组3(组合)

1003次阅读  |  发布于5年以前

前两篇文章对NumPy数组做了基本的介绍,本篇文章对NumPy数组进行较深入的探讨。首先介绍自定义类型的数组,接着数组的组合,最后介绍数组复制方面的问题。

自定义结构数组

通过NumPy也可以定义像C语言那样的结构类型。在NumPy中定义结构的方法如下:

定义结构类型名称;定义字段名称,标明字段数据类型。


    student= dtype({'names':['name', 'age', 'weight'], 'formats':['S32', 'i','f']}, align = True) 

这里student是自定义结构类型的名称,使用dtype函数创建,在第一个参数中,'names'和'formats'不能改变,names中列出的是结构中字段名称,formats中列出的是对应字段的数据类型。S32表示32字节长度的字符串,i表示32位的整数,f表示32位长度的浮点数。最后一个参数为True时,表示要求进行内存对齐。

字段中使用NumPy的字符编码来表示数据类型。更详细的数据类型见下表。

数据类型 字符编码

整数 i

无符号整数 u

单精度浮点数 f

双精度浮点数 d

布尔值 b

复数 D

字符串 S

Unicode U

Void V

在定义好结构类型之后,就可以定义以该类型为元素的数组了:


    a= array([("Zhang", 32, 65.5), ("Wang", 24, 55.2)], dtype =student) 

除了在每个元素中依次列出对应字段的数据外,还需要在array函数中最后一个参数指定其所对应的数据类型。

注:例子来源于张若愚的Python科学计算艺术的29页。更多关于dtype的内容请参考《NumPy for Beginner》一书的第二章。

组合函数

这里介绍以不同的方式组合函数。首先创建两个数组:


    >>> a = arange(9).reshape(3,3) 
    >>> a 
    array([[0, 1, 2], 
       [3, 4, 5], 
       [6, 7, 8]]) 
    >>> b = 2 * a 
    >>> b 
    array([[ 0, 2, 4], 
      [ 6, 8, 10], 
      [12, 14, 16]]) 

水平组合


    >>> hstack((a, b)) 
    array([[ 0, 1, 2, 0, 2, 4], 
      [ 3, 4, 5, 6, 8, 10], 
      [ 6, 7, 8, 12, 14, 16]]) 

也可通过concatenate函数并指定相应的轴来获得这一效果:


    >>> concatenate((a, b), axis=1) 
    array([[ 0, 1, 2, 0, 2, 4], 
      [ 3, 4, 5, 6, 8, 10], 
      [ 6, 7, 8, 12, 14, 16]]) 

垂直组合


    >>> vstack((a, b)) 
    array([[ 0, 1, 2], 
      [ 3, 4, 5], 
      [ 6, 7, 8], 
      [ 0, 2, 4], 
      [ 6, 8, 10], 
      [12, 14, 16]]) 

同样,可通过concatenate函数,并指定相应的轴来获得这一效果。


    >>> concatenate((a, b), axis=0) 
    array([[ 0, 1, 2], 
      [ 3, 4, 5], 
      [ 6, 7, 8], 
      [ 0, 2, 4], 
      [ 6, 8, 10], 
      [12, 14, 16]]) 

深度组合

另外,还有深度方面的组合函数dstack。顾名思义,就是在数组的第三个轴(即深度)上组合。如下:


    >>> dstack((a, b)) 
    array([[[ 0, 0], 
      [ 1, 2], 
      [ 2, 4]], 

      [[ 3, 6], 
      [ 4, 8], 
      [ 5, 10]], 

      [[ 6, 12], 
      [ 7, 14], 
      [ 8, 16]]]) 

仔细观察,发现对应的元素都组合成一个新的列表,该列表作为新的数组的元素。

行组合

行组合可将多个一维数组作为新数组的每一行进行组合:


    >>> one = arange(2) 
    >>> one 
    array([0, 1]) 
    >>> two = one + 2 
    >>> two 
    array([2, 3]) 
    >>> row_stack((one, two)) 
    array([[0, 1], 
      [2, 3]]) 

对于2维数组,其作用就像垂直组合一样。

列组合

列组合的效果应该很清楚了。如下:


    >>> column_stack((oned, twiceoned)) 
    array([[0, 2], 
      [1, 3]]) 

对于2维数组,其作用就像水平组合一样。

分割数组

在NumPy中,分割数组的函数有hsplit、vsplit、dsplit和split。可将数组分割成相同大小的子数组,或指定原数组分割的位置。

水平分割


    >>> a = arange(9).reshape(3,3) 
    >>> a 
    array([[0, 1, 2], 
      [3, 4, 5], 
      [6, 7, 8]]) 
    >>> hsplit(a, 3) 
    [array([[0], 
      [3], 
      [6]]), 
     array([[1], 
      [4], 
      [7]]), 
     array([[2], 
      [5], 
      [8]])] 

也调用split函数并指定轴为1来获得这样的效果:


    split(a, 3, axis=1) 

垂直分割

垂直分割是沿着垂直的轴切分数组:


    >>> vsplit(a, 3) 
    >>> [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])] 

同样,也可通过solit函数并指定轴为1来获得这样的效果:


    >>> split(a, 3, axis=0) 

面向深度的分割

dsplit函数使用的是面向深度的分割方式:


    >>> c = arange(27).reshape(3, 3, 3) 
    >>> c 
    array([[[ 0, 1, 2], 
      [ 3, 4, 5], 
      [ 6, 7, 8]], 

      [[ 9, 10, 11], 
      [12, 13, 14], 
      [15, 16, 17]], 

      [[18, 19, 20], 
      [21, 22, 23], 
      [24, 25, 26]]]) 
    >>> dsplit(c, 3) 
    [array([[[ 0], 
      [ 3], 
      [ 6]], 

      [[ 9], 
      [12], 
      [15]], 

      [[18], 
      [21], 
      [24]]]), 
     array([[[ 1], 
      [ 4], 
      [ 7]], 

      [[10], 
      [13], 
      [16]], 

      [[19], 
      [22], 
      [25]]]), 
     array([[[ 2], 
      [ 5], 
      [ 8]], 

      [[11], 
      [14], 
      [17]], 

      [[20], 
      [23], 
      [26]]])] 

复制和镜像(View)

当运算和处理数组时,它们的数据有时被拷贝到新的数组有时不是。这通常是新手的困惑之源。这有三种情况:

完全不复制

简单的赋值,而不复制数组对象或它们的数据。


    >>> a = arange(12) 
    >>> b = a  #不创建新对象 
    >>> b is a   # a和b是同一个数组对象的两个名字 
    True 
    >>> b.shape = 3,4 #也改变了a的形状 
    >>> a.shape 
    (3, 4) 
        Python 传递不定对象作为参考4,所以函数调用不拷贝数组。
     >>> def f(x): 
    ...  print id(x) 
    ... 
    >>> id(a)  #id是一个对象的唯一标识 
    148293216 
    >>> f(a) 
    148293216 

视图(view)和浅复制

不同的数组对象分享同一个数据。视图方法创造一个新的数组对象指向同一数据。


    >>> c = a.view() 
    >>> c is a 
    False 
    >>> c.base is a  #c是a持有数据的镜像 
    True 
    >>> c.flags.owndata 
    False 
    >>> 
    >>> c.shape = 2,6 # a的形状没变 
    >>> a.shape 
    (3, 4) 
    >>> c[0,4] = 1234  #a的数据改变了 
    >>> a 
    array([[ 0, 1, 2, 3], 
      [1234, 5, 6, 7], 
      [ 8, 9, 10, 11]]) 

切片数组返回它的一个视图:


    >>> s = a[ : , 1:3]  # 获得每一行1,2处的元素 
    >>> s[:] = 10   # s[:] 是s的镜像。注意区别s=10 and s[:]=10 
    >>> a 
    array([[ 0, 10, 10, 3], 
      [1234, 10, 10, 7], 
      [ 8, 10, 10, 11]]) 

深复制

这个复制方法完全复制数组和它的数据。


     >>> d = a.copy()  #创建了一个含有新数据的新数组对象 
    >>> d is a 
    False 
    >>> d.base is a  #d和a现在没有任何关系 
    False 
    >>> d[0,0] = 9999 
    >>> a 
    array([[ 0, 10, 10, 3], 
      [1234, 10, 10, 7], 
      [ 8, 10, 10, 11]]) 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8