前两篇文章对NumPy数组做了基本的介绍,本篇文章对NumPy数组进行较深入的探讨。首先介绍自定义类型的数组,接着数组的组合,最后介绍数组复制方面的问题。
自定义结构数组
通过NumPy也可以定义像C语言那样的结构类型。在NumPy中定义结构的方法如下:
定义结构类型名称;定义字段名称,标明字段数据类型。
1
|
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 |
在定义好结构类型之后,就可以定义以该类型为元素的数组了:
1
|
a = array([(“Zhang”, 32 , 65.5 ), (“Wang”, 24 , 55.2 )], dtype = student)
|
除了在每个元素中依次列出对应字段的数据外,还需要在array函数中最后一个参数指定其所对应的数据类型。
注:例子来源于张若愚的Python科学计算艺术的29页。更多关于dtype的内容请参考《NumPy for Beginner》一书的第二章。
组合函数
这里介绍以不同的方式组合函数。首先创建两个数组:
1
2
3
4
5
6
7
8
9
10
|
>>> 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 ]])
|
水平组合
1
2
3
4
|
>>> hstack((a, b))
array([[ 0 , 1 , 2 , 0 , 2 , 4 ],
[ 3 , 4 , 5 , 6 , 8 , 10 ],
[ 6 , 7 , 8 , 12 , 14 , 16 ]])
|
也可通过concatenate函数并指定相应的轴来获得这一效果:
1
2
3
4
|
>>> concatenate((a, b), axis = 1 )
array([[ 0 , 1 , 2 , 0 , 2 , 4 ],
[ 3 , 4 , 5 , 6 , 8 , 10 ],
[ 6 , 7 , 8 , 12 , 14 , 16 ]])
|
垂直组合
1
2
3
4
5
6
7
|
>>> vstack((a, b))
array([[ 0 , 1 , 2 ],
[ 3 , 4 , 5 ],
[ 6 , 7 , 8 ],
[ 0 , 2 , 4 ],
[ 6 , 8 , 10 ],
[ 12 , 14 , 16 ]])
|
同样,可通过concatenate函数,并指定相应的轴来获得这一效果。
1
2
3
4
5
6
7
|
>>> 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。顾名思义,就是在数组的第三个轴(即深度)上组合。如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> dstack((a, b))
array([[[ 0 , 0 ],
[ 1 , 2 ],
[ 2 , 4 ]],
[[ 3 , 6 ],
[ 4 , 8 ],
[ 5 , 10 ]],
[[ 6 , 12 ],
[ 7 , 14 ],
[ 8 , 16 ]]])
|
仔细观察,发现对应的元素都组合成一个新的列表,该列表作为新的数组的元素。
行组合
行组合可将多个一维数组作为新数组的每一行进行组合:
1
2
3
4
5
6
7
8
9
|
>>> one = arange( 2 )
>>> one
array([ 0 , 1 ])
>>> two = one + 2
>>> two
array([ 2 , 3 ])
>>> row_stack((one, two))
array([[ 0 , 1 ],
[ 2 , 3 ]])
|
对于2维数组,其作用就像垂直组合一样。
列组合
列组合的效果应该很清楚了。如下:
1
2
3
|
>>> column_stack((oned, twiceoned))
array([[ 0 , 2 ],
[ 1 , 3 ]])
|
对于2维数组,其作用就像水平组合一样。
分割数组
在NumPy中,分割数组的函数有hsplit、vsplit、dsplit和split。可将数组分割成相同大小的子数组,或指定原数组分割的位置。
水平分割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
>>> 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来获得这样的效果:
1
|
split(a, 3 , axis = 1 )
|
垂直分割
垂直分割是沿着垂直的轴切分数组:
1
2
|
>>> vsplit(a, 3 )
>>> [array([[ 0 , 1 , 2 ]]), array([[ 3 , 4 , 5 ]]), array([[ 6 , 7 , 8 ]])]
|
同样,也可通过solit函数并指定轴为1来获得这样的效果:
1
|
>>> split(a, 3 , axis = 0 )
|
面向深度的分割
dsplit函数使用的是面向深度的分割方式:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
>>> 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)
当运算和处理数组时,它们的数据有时被拷贝到新的数组有时不是。这通常是新手的困惑之源。这有三种情况:
完全不复制
简单的赋值,而不复制数组对象或它们的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
>>> 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)和浅复制
不同的数组对象分享同一个数据。视图方法创造一个新的数组对象指向同一数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
>>> 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 ]])
|
切片数组返回它的一个视图:
1
2
3
4
5
6
|
>>> 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 ]])
|
深复制
这个复制方法完全复制数组和它的数据。
1
2
3
4
5
6
7
8
9
10
|
>>> 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 ]])
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/sunny2038/article/details/8907736