揭开Python科学计算的面纱

春牛春杖。无限春风来海上。便与春工。染得桃红似肉红。
春幡春胜。一阵春风吹酒醒。不似天涯。卷起杨花似雪花。

  标准的Python中用列表保存一组值,可以当做数组使用,但是由于其值类型任意,所以列表中保存的是指针,这样的话保存一个简单的列表,例如:[1,2,3]需要三个指针和三个对象。对于数值运算来说这样十分耗费内存和CPU。

  Python提供了array 模块,他所提供的array对象和列表不同,能直接保存数值和C语言的一维数组相似,但是他不支持多维数组,也没有各种运算函数,因此也不适合做数值运算。

  NumPy的诞生弥补了这些不足之处,NumPy提供了两种基本的对象:

  1. ndarray:英文全称n-dimensional array object ,他是储存单一数据类型的多维数组,后来统称为数组。
  2. ufunc:英文全称为universal function object , 他是一种能够对数组进行特殊处理的函数。

本文采用1.12版本

>>> import numpy as np
>>> np.__version__
'1.12.0'

ndarray对象


 

  Numpy中使用ndarray对象来表示数组,他是整个库的核心对象,NumPy中所有的函数都是围绕这ndarray对象展开处理的。ndarray的结构不复杂,但是功能十分强大,不但可以用它大量高效的储存数值元素,从而提高数组计算的运算速度,还可以用它和各种扩展库进行数据交换。

创建

  首先需要创建数组才能对其进行运算和操作。可以通过给array() , 函数传递Python的序列对象创建数组,如果传递的是多层嵌套的序列,将创建个多维数组:

>>> a = np.array([1,2,3,4])
>>> b = np.array([5,6,7,8])
>>> c = np.array([[1,2,3,4],[4,5,6,7],[7,8,9,0]])
>>> a
array([1, 2, 3, 4])
>>> b
array([5, 6, 7, 8])
>>> c
array([[1, 2, 3, 4],[4, 5, 6, 7],[7, 8, 9, 0]])
>>> a.shape                    # 查看数组的形状可以通过其 shape属性
(4,)
>>> b.shape
(4,)
>>> c.shape
(3, 4)

  数组a的shape属性只有一个元素是因为他是一维数组 . 而数组C的shape属性有两个元素, 是因为他是二维数组 . 其元素的排序是从高维到低维 . 我们还可以通过修改数组的shape属性,在保持数组元素个数不变的情况下,改变数组每个轴的长度.下面的例子讲数组c的shape属性改为(4,3), 注意从(3,4)到(4,3)不是对数组进行转置, 而是改变每个轴的大小,数组元素在内存中的位置没有变化

>>> c.shape = 4,3
>>> c
array([[1, 2, 3],[4, 4, 5],[6, 7, 7],[8, 9, 0]])

  你应该可以发现(4,3)和(3,4)总结起来不还是12个基本元素么 ? 我们改变总容量行不行 ?

>>> c.shape = 4,2
Traceback (most recent call last):File "<input>", line 1, in <module>c.shape = 4,2
ValueError: cannot reshape array of size 12 into shape (4,2)
>>> c.shape = 4,5
Traceback (most recent call last):File "<input>", line 1, in <module>c.shape = 4,5
ValueError: cannot reshape array of size 12 into shape (4,5)

  当我们设置某个轴的元素个数为 - 1 的时候, 讲自动计算此轴的长度 . 由于数组c有12个元素因此下面的程序讲c的shape属性改为(2,6):

>>> c.shape = 2,-1
>>> c
array([[1, 2, 3, 4, 4, 5],[6, 7, 7, 8, 9, 0]])
>>> c.shape 
(2, 6)

  如果是三维数组我们设置两个 -1 呢 ?( 这个问题好像有点弱智 哈 )  发生错误:只能指定一个位置的维度

>>> c = np.array([[[1,2,3,4],[4,5,6,7],[7,8,9,0]],[[1,2,3,4],[4,5,6,7],[7,8,9,0]
]])
>>> c.shape
(2, 3, 4)
>>> c.shape = 3,-1,-1
Traceback (most recent call last):File "<input>", line 1, in <module>c.shape = 3,-1,-1
ValueError: can only specify(指定) one unknown dimension(维度)

  使用数组的reshape方法, 可以创建指定形状的新数组, 而原数组的形状保持不变:

>>> a
array([1, 2, 3, 4])
>>> d = a.reshape((2,2))
>>> d
array([[1, 2],[3, 4]])

  汇编/C语言 中毒比较深的同学可能问了, 那么储存方式呢 ? 其实数组a和d是共享储存空间的,因此如果修改其中任意一个数组的元素都会同事修改另一个数组的内容, 注意在下面的例子中 , 数组d中的2也被改变成了100:(很好,很强大.)

>>> a
array([1, 2, 3, 4])
>>> d = a.reshape((2,2))
>>> d
array([[1, 2],[3, 4]])
>>> a[1]
2
>>> a[1] = 100
>>> a
array([  1, 100,   3,   4])
>>> d
array([[  1, 100],[  3,   4]])

元素类型

  数组的元素类型可以通过dtype来获得, 在前面的例子中, 创建数组所用到的序列的元素都是证书, 因此创建的数组的元素类型也都是整数, 我用的是Ubuntu64位, 所以我显示的类型是int类型64位, 如果你的是32 位可能你用的是32位的系统.

>>> c
array([[1, 2, 3, 4, 4, 5],[6, 7, 7, 8, 9, 0]])
>>> c.dtype
dtype('int64')

  如果有编译器有代码提示的同学可能就会发现, 那个dtype了, 在没有介绍前面的东西的时候你可能还以为这是个什么鬼 ? 现在应该知道他是用于指定元素类型用的了吧?

>>> ai32 = np.array(
┌──────────────────────────────────────────────────────────────┐
│ np.array: (object, dtype=None, copy=True, order='K',         │
│ subok=False, ndmin=0)                                        │
│ array           array2string    array_equal                  │
│ array_equiv     array_repr      array_split                  │
│ array_str                                                    │
│ array(object, dtype=None, copy=True, order='K', subok=False, │
│  ndmin=0)                                                    │
│                                                              │
│ Create an array.                                             │
│                                                              │
│ Parameters                                                   │
│ ----------                                                   │
│ object : array_like                                          │
│     An array, any object exposing the array interface, an ob │
│ ject whose                                                   │
│     __array__ method returns an array, or any (nested) seque │
│ nce.                                                         │
│ dtype : data-type, optional                                  │
└──────────────────────────────────────────────────────────────┘

 

>>> ai32 = np.array([1,2,3,4],dtype = np.int32)
>>> ai32
array([1, 2, 3, 4], dtype=int32)
>>> ai32.shape
(4,)
>>> af = np.array([1,2,3,4],dtype = np.float)
>>> af
array([ 1.,  2.,  3.,  4.])
>>> ac = np.array([1,2,3,4],dtype = np.complex)
>>> ac
array([ 1.+0.j,  2.+0.j,  3.+0.j,  4.+0.j])
>>> ac.shape
(4,)
>>> ai32.dtype
dtype('int32')
>>> af.dtype
dtype('float64')
>>> ac.dtype
dtype('complex128')

 

  在上面的例子中传递给dtype参数的都是类型对象, 其中类型对象都是NumPy定义的数据类型. 当然内置的也有并且其效果和内置的相同.

  在需要指定dtype参数的时候, 也可以传递一个字符串来表示元素的数值类型. NumPy中每个数值类型都有集中字符串的表达方式, 字符串和类型之间的对用关系都储存在typeDict字典中,下面的程序获得与float64类型对应的所有键值.

>>> [key for key, value in np.typeDict.items() if value is np.float64]
[12, 'd', 'float_', 'float', 'double', 'Float64', 'f8', 'float64']

  好吧翻译一下.

>>> for key,value in np.typeDict.items():
...     if value is np.float64:
...         value,key
...         
...     
... 
(<class 'numpy.float64'>, 12)
(<class 'numpy.float64'>, 'd')
(<class 'numpy.float64'>, 'float_')
(<class 'numpy.float64'>, 'float')
(<class 'numpy.float64'>, 'double')
(<class 'numpy.float64'>, 'Float64')
(<class 'numpy.float64'>, 'f8')
(<class 'numpy.float64'>, 'float64')

  完整的类型列表可以通过下面的语句获得, 他讲typeDict字典中的所有值转化为一个集合,从而去除重复项. ( 重复项 值只有这么多, 但是一个值可以有很多个键. )

>>> set(np.typeDict.values())
{<class 'numpy.float128'>, <class 'numpy.uint64'>, <class 'numpy.int64'>, <class'numpy.str_'>, <class 'numpy.complex128'>, <class 'numpy.float64'>, <class 'num
py.uint32'>, <class 'numpy.int32'>, <class 'numpy.bytes_'>, <class 'numpy.comple
x64'>, <class 'numpy.float32'>, <class 'numpy.uint16'>, <class 'numpy.int16'>, <
class 'numpy.bool_'>, <class 'numpy.timedelta64'>, <class 'numpy.float16'>, <cla
ss 'numpy.uint8'>, <class 'numpy.int8'>, <class 'numpy.object_'>, <class 'numpy.
datetime64'>, <class 'numpy.uint64'>, <class 'numpy.int64'>, <class 'numpy.void'
>, <class 'numpy.complex256'>}

  上面显示的数值类型与数组的dtype属性是不同的对象. 通过dtype 对象的type属性可以获得与之对应的数值类型.

>>> c.dtype   # 我的理解是这里的int64 指的是数组中的元素是 int64储存的
dtype('int64')
>>> c.dtype.type  # 这里应该是数组本身是按照 numpy.int64的方式储存的 , 不知道对不对, 如果不对我会回来修改的.
<class 'numpy.int64'>

  通过NumPy的数值类型也可以创建数值对象, 下面创建一个16位的符号整数对象, 它与Python的整数对象不同的是,他的取值范围有限, 因此计算200*200 会溢出,得到一个负数.

>>> a = np.int16(200)
>>> a*a
__console__:1: RuntimeWarning: overflow encountered in short_scalars
-25536
>>> a+a
400

  另外值得指出的是, NumPy的数值对象的运算速度比Python的内置类型的运算速度慢的很多, 如果程序中需要大量的对单个数值进行计算, 应当避免使用NumPy的数值对象. 使用astype()方法可以对数组的元素类型进行转换.

>>> t1 = np.array([1,2,3,4.0],dtype = np.float64)
>>> t2 = np.array([1,2,3,4],dtype = np.complex)
>>> t3 = t1.astype(np.int64)
>>> t4 = t2.astype(np.complex256)
>>> t1.dtype
dtype('float64')
>>> t2.dtype
dtype('complex128')
>>> t3.dtype
dtype('int64')
>>> t4.dtype
dtype('complex256')
>>> t4.dtype.type
<class 'numpy.complex256'>

 自动生成数组

  前面的例子都是先创建一个Python的序列对象,然后通过array() 将其装华为数组, 这样做显然效率不高 , 因此NumPy 提供了很多专门用于创建数组的函数 , 下面的每个函数都有一些关键字参数. 具体用法请查看函数说明.

  arange() 类似于内置函数range() , 通过指定开始值, 终止值, 和步长来创建表示等差数列的一维数组, 注意所得到的结果不包含终止值.

>>> np.arange(0,1,0.1)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

  linspace 通过指定开始值和终止值以及步数,来创建一个数组. (line space : 线性等分 ?)   这个默认包含终止值.( 不然没法弄了)

>>> np.linspace(0,8,9)
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.])

  当然我们可以通过指定endpoint的真假 来选择是否包含终止值.

>>> np.linspace(0,8,9)
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.])
>>> np.linspace(0,8,9,endpoint = False)
array([ 0.        ,  0.88888889,  1.77777778,  2.66666667,  3.55555556,4.44444444,  5.33333333,  6.22222222,  7.11111111])
>>> 0.88888888*9
7.99999992
>>> np.linspace(0,7,9)
array([ 0.   ,  0.875,  1.75 ,  2.625,  3.5  ,  4.375,  5.25 ,  6.125,  7.   ])

  logspace()和linspace()类似, 不过他所创建的数组是等比数列.下面例子产生从100 到 10,有5个元素的等比数列, 注意起始值0 代表100 终止值 2 代表 102 

>>> np.logspace(0,2,num = 4,endpoint = False,base = 4.0,dtype = np.float128)
array([ 1.0,  2.0,  4.0,  8.0], dtype=float128)

  我用的bpython 在写代码的时候会有函数说明

 np.logspace: (start, stop, num=50, endpoint=True, base=10.0, │
│ dtype=None)                                                  │
│ logspace                                                     │
│ Return numbers spaced evenly on a log scale.                 │
│                                                              │
│ In linear space, the sequence starts at ``base ** start``    │
│ (`base` to the power of `start`) and ends with ``base ** sto │
│ p``                                                          │
│ (see `endpoint` below).                                      │
│                                                              │
│ Parameters                                                   │
│ ----------                                                   │
│ start : float                                                │
│     ``base ** start`` is the starting value of the sequence. │
│ stop : float                                                 │
│     ``base ** stop`` is the final value of the sequence, unl │
│ ess `endpoint`                                               │
│     is False.  In that case, ``num + 1`` values are spaced o │
└──────────────────────────────────────────────────────────────┘

   zeros(), ones(), empty()可以创建指定形状的和类型的数组. 其中empty() 只分配数组所使用的内存, 不对数组进行初始化操作, 所以他的运行速度应该是最快的. 下面的程序位创建一个形状为(2,3), 元素类型位整数的数组, 注意其中的元素没有被初始化.

  

>>> np.empty((2,3),np.int)
array([[              0,        10914432,        10743840],[140263681062408, 140263663167672, 140263663165992]])

   而zeros() 将数组初始化位0, ones()将数组元素初始化为1 . 下面创建一个长度位4, 而元素类型为整数的一维数组, 并且元素全部被初始化位0 :

>>> np.zeros(4,np.int)
array([0, 0, 0, 0])

  full() 可以讲元素初始化为指定的值:

>>> np.full((2,3),4,np.int64)
array([[4, 4, 4],[4, 4, 4]])

  编译器有代码提示的同学可能很早就注意到了, zeros_like(), ones_like(), empty_like(), full_like() 等函数了. 这些函数创建与参数数组的形状和类型相同的数组, 因此zeros_like(a) 和zeros(a.shape,a.dtype)的效果相同

>>> np.full(4,np.pi)
array([ 3.14159265,  3.14159265,  3.14159265,  3.14159265])
>>> np.full((4,2),np.pi)
array([[ 3.14159265,  3.14159265],[ 3.14159265,  3.14159265],[ 3.14159265,  3.14159265],[ 3.14159265,  3.14159265]])

  frombuffer(), fromstring(), fromfile() 等函数可以从字节序列, 或者文件创建数组. 下面以fromstring()为例子 , 展示他们的用法,  很明显这里值为-1 的一般都是自动计算.

>>> s = 'abcdefgh'
>>> #python的字符串实际上是一个字节序列每个字符,占有一个字节. 因此如果从s中创建L编码
>>> np.fromstring(s,np.int8,5)
array([ 97,  98,  99, 100, 101], dtype=int8)
>>> np.fromstring(s,np.int8,-1)
array([ 97,  98,  99, 100, 101, 102, 103, 104], dtype=int8)

存取元素

  可以使用和列表相同的方式对数组的元素进行存取:

>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
  1. a[5]: 用整数作为下标可以获取数组中的某个元素.
  2. a[3:5]: 用切片作为下标获取数组的一部分, 不包括a[5].
  3. a[:5]: 切片中省略开始下标, 表示从 a[0] 开始.
  4. a[:-1]: 下标使用负数, 表示从数组最后往前数.

  灵活灵活滴 .

>>> a[5]
5
>>> a[5:]
array([5, 6, 7, 8, 9])
>>> a[5:6]
array([5])
>>> a[5:8]
array([5, 6, 7])
>>> a[5:-1]
array([5, 6, 7, 8])
>>> a[-3:-1]
array([7, 8])
>>> a[3:-1]
array([3, 4, 5, 6, 7, 8])

 

  当使用证书列表对数组元素进行存取的时候,将使用列表中的每个元素作为下表, 使用列表作为下标得到的数组不和原始数组共享数据.

>>> x = np.arange(10,1,-1)
>>> x
array([10,  9,  8,  7,  6,  5,  4,  3,  2])
>>> a = x[[3,3,1,8]]
>>> a
array([7, 7, 9, 2])
>>> b = x[[3,3,-3,8]]
>>> b
array([7, 7, 4, 2])

 

  * 我们也可以通过上面的方式来进行批量赋值 .

>>> x[[0,1,2,3]] = 9,8,7,6
>>> x[[0,1,2,3]]
array([9, 8, 7, 6])
>>> x
array([9, 8, 7, 6, 6, 5, 4, 3, 2])

 

   * 我们可以通过数组为下标的情况来获得一个新的数组, 在一位数组中是这样, 在多维中也是这样.

array([10,  9,  8,  7,  6,  5,  4,  3,  2])
>>> x[np.array([[3,3,1,8],[3,3,-3,8]])]
array([[7, 7, 9, 2],[7, 7, 4, 2]])

 

  * 当使用不二数组b 作为存取数组 x 中的元素时, 将获得数组x 中与 数组b 中True对应的元素. 使用布尔数组作为下表获得的数组不和原始数组共享数据内存,  注意这种方式只对应与不二数组, 而不能使用布尔列表.

>>> x[np.array([True,False,True])]
__console__:3: VisibleDeprecationWarning: boolean index did not match indexed ar
ray along dimension 0; dimension is 9 but corresponding boolean dimension is 3
array([10,  8])

 

  * 当布尔数组的长度不够的时候, 不够的部分都当做False

  *布尔数组一般不是手工产生的, 而是通过使用布尔运算的ufunc 函数产生的, 关于ufunc 函数请参照下一节课的介绍, 下面我们举一个简单的例子说明布尔数组下标的用法:

>>> np.random.randint(0,10,6)
array([1, 9, 5, 0, 7, 2])

 

>>> x[x>5]
array([10,  9,  8,  7,  6])
>>> x
array([10,  9,  8,  7,  6,  5,  4,  3,  2])

 

  多维数组

  多维数组的存取和一维数组类似, 因为多维数组有多个轴, 所以他的下标需要用多少个值来表示, NumPy采用元祖作为数组的下标, 元祖中的每个元素和数组的每个轴对应.

  为什么使用元祖作为下标.

  Python的下标语法(用[] 存取序列中的元素)本身并不支持多维, 但是可以使用任何对象作为下标, 因此 NumPy使用元祖作为下标存取数组中的元素, 使用元祖可以很方便的表示多个轴的下标, 虽然在Python程序中经常使用圆括号将元祖中的元素括起来, 但其实元祖的使用语法,只需要逗号隔开元素即可, 例如 x,y = y,x 就是用元祖交换变量值的一个例子. 因此 a[1,2]和啊a[(1,2)] 完全相同, 都是使用元祖(1,2) 作为数组a 的下标.

  `上面的二维数组是怎样创建的? 其实他是一个加法表, 由纵向量(0,10,20,30,40,50)和横向量(0,1,2,3,4,5)的元素想家而得的, 可以使用下面的语句创建他, 至于其原理, 将在后面的章节讨论.

>>> a = np.arange(0,60,10).reshape(-1,1) + np.arange(0,5)
>>> a
array([[ 0,  1,  2,  3,  4],[10, 11, 12, 13, 14],[20, 21, 22, 23, 24],[30, 31, 32, 33, 34],[40, 41, 42, 43, 44],[50, 51, 52, 53, 54]])

 

  有的同学应该很好奇上面的图中的是怎样让a[0,3:5] , a[4:,4:]等切片操作找到自己的位置的 ?  其中的第0 个元素个 第 0 轴对应, 第一个元素和第一轴对应 , 然后就是普通的一维数组切片操作了, 在不同的维度中可以对应出来他们相交的点 , 相交的点就是 该切片操作表示的点.

  

 

  如果下标元祖中只包含整数和切片, 那么得到的数组和原始数组共享数据 , 他是原数组的视图 , 下面的例子中, 数组b是a的视图 , 他们共享数据 , 因此修改b[0]的时候, 数组a中对应的元素也会被修改.

>>> b = a[0,3:5]
>>> b
array([3, 4])
>>> b[0] = 12312313
>>> b
array([12312313,        4])
>>> a
array([[       0,        1,        2, 12312313,        4],[      10,       11,       12,       13,       14],[      20,       21,       22,       23,       24],[      30,       31,       32,       33,       34],[      40,       41,       42,       43,       44],[      50,       51,       52,       53,       54]])

 

 

  切片对象(slice)

  根据Python的语法,在[]中可以使用冒号隔开的两个或者三个整数表示切片, 但是单独生成切片对象时需要使用slice() 来创建. 他有三个参数值, 开始,结束,间隔. 当这些值需要省略时可以使用None, 例如

>>> a[:,2]
array([ 2, 12, 22, 32, 42, 52])
>>> a[slice(None,None,None),2]
array([ 2, 12, 22, 32, 42, 52])

 

>>> a[slice(2,3),]
array([[20, 21, 22, 23, 24]])
>>> b = a[slice(2,3),] 
>>> b
array([[20, 21, 22, 23, 24]])
>>> a
array([[ 0,  1,  2,  3,  4],[10, 11, 12, 13, 14],[20, 21, 22, 23, 24],[30, 31, 32, 33, 34],[40, 41, 42, 43, 44],[50, 51, 52, 53, 54]])
>>> b[0]
array([20, 21, 22, 23, 24])
>>> b[0][0] = 123123
>>> b
array([[123123,     21,     22,     23,     24]])
>>> a
array([[     0,      1,      2,      3,      4],[    10,     11,     12,     13,     14],[123123,     21,     22,     23,     24],[    30,     31,     32,     33,     34],[    40,     41,     42,     43,     44],[    50,     51,     52,     53,     54]])

 

  用Python的内置函数slice()创建下标实际上是比较麻烦的, 因此NumPy提供了一个s_对象来帮助我们创建数组下标, 请注意s_实际上是IndexExpression类的一个对象.(因为动不动就要填写None)

>>> b = a[slice(2,,1),] File "<input>", line 1b = a[slice(2,,1),]^
SyntaxError: invalid syntax

 

  所以我们可以使用NumPy所提供的s_对象来帮助我们创建数组下标.

 

>>> a = np.arange(0,60,10).reshape(-1,1) + np.arange(0,5)
>>> a
array([[ 0,  1,  2,  3,  4],[10, 11, 12, 13, 14],[20, 21, 22, 23, 24],[30, 31, 32, 33, 34],[40, 41, 42, 43, 44],[50, 51, 52, 53, 54]])
>>> b = a[slice(None,None,2),slice(2,None,None)]
>>> b
array([[ 2,  3,  4],[22, 23, 24],[42, 43, 44]])
>>> c = a[np.s_[::2,2:]]
>>> c
array([[ 2,  3,  4],[22, 23, 24],[42, 43, 44]])

 

  s_为什么不是函数?

    根据Python的语法, 只有在中括号[] 中才能使用以冒号隔开的切片语法, 如果s_ 是函数的话, 那么这些切片必须使用slice() 创建, 类似的对象还有mgrid 和 ogrid等, Python的下标语法实际上会调用getitem() 方法, 因此我们可以很容易实现s_对象的功能.

  在a[(0,1,2,3),(1,2,3,4)] 中, 下标仍然是一个有两个元素的元祖, 元祖中的每个元素都是一个整数元祖, 分别对应数组中的第0 轴和第 1 轴, 从两个序列的对应位置取出两个整数组成下标, 于是得到的结果是, a[0,1],a[1,2], a[2,3], a[3,4].

  在a[3:,[0,2,5]]中, 第0轴的下标是一个切片对象, 它选取第三行之后的所有行, 第一轴的下标是整数列表, 它选取 第0,2,5列.

  在a[mask,2]中, 第0轴的下标是一个布尔数组,他选取第0,2,5行,第一轴的下标是2.

>>> x = np.array([[0,1],[2,3]])
>>> y = np.array([[-1,-2],[-3,-4]])
>>> a[x,y]
array([[ 5, 14],[23, 32]])

 

结构数组

  在C语言中我们可以通过struct 关键字定义结构类型, 结构中的字段占据连续的内存空间. 类型相同的两个结构所占用的内存大小相同, 因此可以很容易的定义结构数组, 和C语言一样, 在NumPy中也很容易堆这种结构数组进行操作, 只要NumPy中的结构定义和C语言中的结构定义相同, 就可以很方便的读取C语言结构数组的二进制数据, 将其转化为NumPy的结构数组.

  假设 我们需要定义一个结构数组, 他的每个元素都有name , age 和 weight字段. 在NumPy中可以如下定义:

>>> persontype = np.dtype({
... 'names':['name','age','weight'],
... 'formats':['S30','i','f']},align = True)
>>> a = np.array([('zhang',32,75.5),('Wang',24,65.2)],dtype = persontype)
>>> a[1]
(b'Wang', 24,  65.19999695)

 

  我们先创建一个 persontype 的dtype对象, 他的参数是一个描述结构类型的各个字段的字典. 字典有两个键, 'name'和'format'. 每个键对应的值都是一个列表. 'names' 定义结构中的每个字段的名称, 而format 则定义为每个字段的类型, 我们这里使用类型字符串定义字符类型.

  •   'S30' 长度位30个字节的字符串类型. 由于结构中的每个元素的大小必须固定, 因此需要指定字符串的长度.
  •        ' i '  32位的整数类型相当于np.int32 . 
  •        ' f ' 32位的单精度浮点数.类型 相当于 np.float32

  然后调用array() 以创建数组, 通过dtype 参数指定所创建的数组的元素类型为 persontype. 下面查看 a的数组类型

>>> a.dtype
dtype({'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets'
:[0,32,36], 'itemsize':40}, align=True)

 

  还可以用包含多个元祖的列表来描述结构的类型:

dtype([('name','|S30'),('age','<i4'),('weight','<f4')])

 

  其中形如 "字段名,类型描述"的元祖描述了结构中的每个字段, 类型字符串前面的'|','<',">"等字符表示字段值的字节顺序:

  • | : 忽视字节顺序
  • <: 低位字节在前, 即小端模式.
  • >: 高位字节在前, 即大端模式.
  • 结构数组的存储方式和一般的数组相同, 通过下标能过取得其中的元素, 注意元素的值看上去像是数组, 实际上是结构.
>>> a[0]
(b'zhang', 32,  75.5)
>>> a[0].dtype
dtype({'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets'
:[0,32,36], 'itemsize':40}, align=True)
>>> a[0]['name']
b'zhang'
>>> a[0]['age']
32

 

   a[0] 是一个结构元素, 他和数组a 共享内存数据, 因此可以通过修改它的字段来改变原始数组中对应元素的字段.

>>> c = a[1]
>>> c
(b'Wang', 24,  65.19999695)
>>> c['age'] = 12312312312
>>> a[1]
(b'Wang', -572589576,  65.19999695)  # 溢出了

 

 

>>> b = a['age']
>>> b
array([        32, -572589576], dtype=int32)
>>> b[0] = 40
>>> b
array([        40, -572589576], dtype=int32)
>>> a[0]['age']
40

 

 

   我们可以通过a.tostring()或者a.tofile的方法,可以将数组a位2进制的方式转换成字符串或写入文件。

 

转载于:https://www.cnblogs.com/A-FM/p/6517500.html

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

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

相关文章

TeamCity构建依赖项

介绍 构建依存关系的主题既不重要也不是次要的。 各种构建工具从不同的角度处理此主题&#xff0c;从而提供各种解决方案&#xff0c;每种解决方案都有其优点和缺点。 熟悉发行版和快照依赖项的Maven和Gradle用户可能不了解TeamCity快照依赖项&#xff0c;或者认为他们与Maven…

复选框操作checked选中为true,反之为False,也可以赋值为true,false

转载于:https://www.cnblogs.com/shiluoliming/p/6518236.html

从0开始学习 GitHub 系列汇总笔记

本文学习自Stromzhang, 原文地址请移步&#xff1a;从0开始学习 GitHub 系列汇总 我的笔记&#xff1a; 0x00 从0开始学习GitHub 系列之[初识GitHub] GitHub 影响力 a.全球顶级科技公司纷纷加入 GitHub &#xff0c;并贡献他们自己的项目代码 Google: https://github.com/goog…

SOA示例应用程序

SOA描述了一组用于创建松散耦合的&#xff0c;基于标准的&#xff0c;与业务相关的服务的模式&#xff0c;由于描述&#xff0c;实现和绑定之间的关注点分离&#xff0c;因此提供了新的灵活性。 近年来&#xff0c;至少在参与大多数信息技术活动的人们中&#xff0c;面向服务的…

Repeater 中TextBox 触发TextChanged事件

两种方法 1.TextBox 绑定TextChanged 并设置AutoPostBack "true" &#xff0c;如果不设置AutoPostBack "true"则不会触发TextChanged事件&#xff0c;然后在对应的方法里面循环Repeater查找改变项 部分代码 <ItemTemplate ><tr><td style &…

真机调试问题

1.拔掉插头重新插入 2.转载于:https://www.cnblogs.com/sanvow/p/5633976.html

ANTLR教程– Hello Word

Antlr代表另一种语言识别工具。 该工具能够为任何计算机语言生成编译器或解释器。 除了明显的用途&#xff08;例如需要解析一种真正的“大型”编程语言&#xff0c;例如Java&#xff0c;PHP或SQL&#xff09;外&#xff0c;它还可以帮助执行更小&#xff0c;更常见的任务。 每…

centOS 6.5安装python和nginx

一、安装python3.5 1、安装python3.5 2、安装pip并升级到最新 下载wget --no-check-certificate https://github.com/pypa/pip/archive/1.5.5.tar.gz 注意&#xff1a;wget获取https的时候要加上&#xff1a;--no-check-certificate tar zvxf 1.5.5.tar.gz #解压文件 cd pip…

插件化编程实现的一份糖炒栗子~~

迷茫的原因是因为想得太多&#xff0c;做得太少。因为只是 想 真的很容易&#xff0c;转瞬之间就会产生无数个念头&#xff0c;或许是该做点什么了吧。 但是整个人都是懒的&#xff0c;是废的&#xff0c;是大脑控制不住自己的行为的。解决方案唯有一步一步的去把行为变成习惯。…

用C#来学习唐诗三百首和全唐诗

Begin 最近把项目做完了&#xff0c;闲来无事&#xff0c;就想做点好玩的事情&#xff0c;刚好前几天下载了【唐诗三百首】和【全唐诗】这两个txt文件&#xff0c;正好用C#来整理一下。 然后导出QData格式&#xff0c;可以给其他软件读取。 以后弄个开机自动显示一句诗&#xf…

sts java配置tomcat_STS配置Tomcat.9.0

今天&#xff0c;心血来潮&#xff0c;弄了一下STS,按着建立WEB项目的方式建立工程。一、新建工程(FILE --NEW--Dynamic Web project)二、输入项目名称&#xff0c;TestWeb&#xff0c;然后下一步&#xff0c;点击FInish.三、新建index.jsp并打开index.jsp,书写测试成功&#x…

javaweb国际化

根据数据的类型不同&#xff0c;国际化分为2类&#xff1a;静态数据国际化和动态数据的国际化。 静态数据&#xff0c;包括 “标题”、“用户名”、“密码”这样的文字数据。 动态数据&#xff0c;包括日期、货币等可以动态生成的数据。 国际化涉及到java.util.Locale和java.ut…

20145335郝昊《网络攻防》Bof逆向基础——ShellCode注入与执行

20145335郝昊《网络攻防》Bof逆向基础——ShellCode注入与执行 实验原理 关于ShellCode&#xff1a;ShellCode是一段代码&#xff0c;作为数据发送给受攻击服务器&#xff0c;是溢出程序和蠕虫病毒的核心&#xff0c;一般可以获取权限。我们将代码存储到对方的堆栈中&#xff0…

玩转Android之加速度传感器的使用,模仿微信摇一摇

Android系统带的传感器有很多种&#xff0c;最常见的莫过于微信的摇一摇了&#xff0c;那么今天我们就来看看Anroid中传感器的使用&#xff0c;做一个类似于微信摇一摇的效果。 OK ,废话不多说&#xff0c;我们就先来看看效果图吧&#xff1a; 当我摇动手机的时候这里的动画效果…

Java两种设计模式_23种设计模式(11)java策略模式

23种设计模式第四篇&#xff1a;java策略模式定义&#xff1a;定义一组算法&#xff0c;将每个算法都封装起来&#xff0c;并且使他们之间可以互换。类型&#xff1a;行为类模式类图&#xff1a;策略模式是对算法的封装&#xff0c;把一系列的算法分别封装到对应的类中&#xf…

JAXB自定义绑定– Java.util.Date / Spring 3序列化

JaxB可以处理Java.util.Date序列化&#xff0c;但是需要以下格式&#xff1a; “ yyyy-MM-ddTHH&#xff1a;mm&#xff1a;ss ”。 如果需要将日期对象格式化为另一种格式怎么办&#xff1f; 我有同样的问题时&#xff0c;我正在同春MVC 3和Jackson JSON处理器 &#xff0c;最…

双足机器人简单步态生成

让机器人行走最简单的方法是先得到一组步态曲线&#xff0c;即腿部每个关节随时间运动的角度值。可以在ADAMS或3D Max、Blender等软件中建立好机构/骨骼模型&#xff0c;设计出脚踝和髋关节的运动曲线&#xff0c;然后进行逆运动学解算&#xff0c;测量每个关节在运动过程中的转…

重新访问了访客模式

访客模式是面向对象设计中最被高估但又被低估的模式之一。 高估了它&#xff0c;因为它常常被选择得太快&#xff08; 可能是由建筑宇航员选择的 &#xff09;&#xff0c;然后以错误的方式添加时会膨胀本来非常简单的设计。 如果您不遵循教科书示例&#xff0c;那么它可能会非…

ASP.NET—013:实现带控件的弹出层(弹出框)

http://blog.csdn.net/yysyangyangyangshan/article/details/38458169 在页面中用到弹出新页面的情况比较多的&#xff0c;一般来说都是使用JS方法showModalDialog("新页面相对路径?参数1&参数2",window,"新页面样式");然后会新弹出一个模态的page页。…

java 二进制 归属权限_【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】...

一、权限计算相关分析1.如何存储权限首先说一下权限保存的问题&#xff0c;一个系统中最多有多少权限呢&#xff1f;一个大的系统中可能有成百上千个权限需要管理。怎么保存这么多的权限&#xff1f;首先&#xff0c;我们使用一个数字中的一位保存一种权限&#xff0c;那么如果…