Python最好用的科学计算库:NumPy快速入门教程(二)
由iquant创建,最终由iquant 被浏览 12 用户
本文接上一篇:Python最好用的科学计算库:NumPy快速入门教程(一)
形状操作
首先导入numpy库
>>> import numpy as np
改变数组的形状
数组的形状由每个维度的元素的数量决定。
>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[7., 1., 0., 7.],
[7., 3., 3., 4.],
[3., 9., 2., 9.]])
>>> a.shape #数组的形状
(3, 4)
数组的形状能够通过很多命令改变。以下的三个命令都能返回一个被改变的数组,但是并不改变原数组。
>>> a.ravel() # 返回被平坦化的数组
array([7., 1., 0., 7., 7., 3., 3., 4., 3., 9., 2., 9.])
>>> a.reshape(6,2) # 返回一个改变形状的数组
array([[7., 1.],
[0., 7.],
[7., 3.],
[3., 4.],
[3., 9.],
[2., 9.]])
>>> a.T # 返回一个被转置的数组
array([[7., 7., 3.],
[1., 3., 9.],
[0., 3., 2.],
[7., 4., 9.]])
>>> a.T.shape
(4, 3)
>>> a.shape # 原数组的形状不变
(3, 4)
ravel()
返回结果的元素顺序一般来说C语言的风格,也就是说,最右的维度先变化,所以,返回结果的排列是a[0,0]
之后是a[0,1]
。如果数组的形状改变了,依然会采用c语言风格的处理方式。NumPy一般生成数组在内存中就是按照这种顺序存储,所以ravel()
一般不会复制参数,但是如果数组是通过切片或其他非一般的方式创建的,可能就需要复制了。ravel()
和reshape()
函数也可以通过设置一个可选参数使用FORTRAN
语言风格,这二种风格下,最左的维度先变化。
reshape
函数返回的是改变了形状数组,而resize
方法改变的是数组本身的形状。
>>> a
array([[7., 1., 0., 7.],
[7., 3., 3., 4.],
[3., 9., 2., 9.]])
>>> a.resize((2,6))
>>> a # resize 之后,a的形状变了,这是与reshape的区别
array([[7., 1., 0., 7., 7., 3.],
[3., 4., 3., 9., 2., 9.]])
如果一个维度被设置为-1,那么这个维度的大小将会自动计算。
>>> a.reshape(3,-1)
array([[7., 1., 0., 7.],
[7., 3., 3., 4.],
[3., 9., 2., 9.]])
堆叠不同的数组
多个数组能够沿着不同维度被堆叠在一起。
>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[7., 8.],
[1., 2.]])
>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[7., 4.],
[2., 6.]])
>>> np.vstack((a,b))
array([[7., 8.],
[1., 2.],
[7., 4.],
[2., 6.]])
>>> np.hstack((a,b))
array([[7., 8., 7., 4.],
[1., 2., 2., 6.]])
column_stack
函数将一维数组看做列向量堆叠成二维数组。当被堆叠的数组是二维时,它的作用与hstack
一样。
>>> from numpy import newaxis
>>> np.column_stack((a,b)) # 使用column_stack堆叠二维数组和上面我们使用hstack时得到的结果一样
array([[7., 8., 7., 4.],
[1., 2., 2., 6.]])
>>> a = np.array([4.,2.])
>>> b = np.array([3.,8.])
>>> np.column_stack((a,b)) # 当被堆叠的数组是一维数组时,返回的结果还是二维数组
array([[4., 3.],
[2., 8.]])
>>> np.hstack((a,b)) # 使用hstack堆叠一维数组,返回的还是一维数组,这是与column_stack的不同
array([4., 2., 3., 8.])
>>> a[:,newaxis] # 通过newaxis能够为数组添加维度
array([[4.],
[2.]])
>>> np.column_stack((a[:,newaxis],b[:,newaxis]))
array([[4., 3.],
[2., 8.]])
>>> np.hstack((a[:,newaxis],b[:,newaxis])) # 添加维度之后再使用hstack就可以得到和column_stack一样的结果
array([[4., 3.],
[2., 8.]])
另外,对于任意数组row_stack与vstack的作用相同。通常,对于大于二维的数组,hstack作用在第二个维度上,而vstack作用在第一个维度上,而concatenate函数允许用户通过设置一个可选参数决定连接应该发生在哪个维度。
注意
在一些复杂的情况下, 使用r_
和 c_
创建数组非常实用. 他们允许使用范围表达符号:
>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])
当作用在数组时,r_ 和 c_ 的作用与vstack和hstack一样,但是允许我们通过可选参数决定连接发生在哪个维度。
将数组拆分为更小的数组
使用hsplit
,你可以沿着水平方向拆分数组,即可以通过指定平均切分的数量,也可以通过指定切分的列来实现。
>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[0., 2., 5., 6., 0., 2., 0., 2., 1., 5., 6., 2.],
[3., 3., 2., 3., 6., 8., 8., 5., 6., 2., 0., 2.]])
>>> np.hsplit(a,3) # 延水平方向切分为3个相同大小的数组
[array([[0., 2., 5., 6.],
[3., 3., 2., 3.]]), array([[0., 2., 0., 2.],
[6., 8., 8., 5.]]), array([[1., 5., 6., 2.],
[6., 2., 0., 2.]])]
np.hsplit(a,(3,4)) # 从第3第4列切分a
[array([[0., 2., 5.],
[3., 3., 2.]]), array([[6.],
[3.]]), array([[0., 2., 0., 2., 1., 5., 6., 2.],
[6., 8., 8., 5., 6., 2., 0., 2.]])]
vsplit
沿着垂直方向切分,array_split
可以指定沿着哪个维度切分。
复制与Views
当操作数组时,有时候数据被复制到一个新的数组,而有时候又没有。这经常困扰新手,以下是三种情况。
不复制
简单的赋值语句不会复制数组对象或者他们的值。
>>> a = np.arange(12)
>>> b = a # 简单的赋值不会复制新的对象
>>> b is a # a和b是同一个数组的两个不同的名称而已
True
>>> b.shape = 3,4 # 改变b的话也会改变a
>>> a.shape
(3, 4)
Python将可变对象作为引用传递,因此函数调用不会复制。
>>> def f(x):
... print(id(x))
...
>>> id(a) # id是一个对象的唯一标识符
4557575552
>>> f(a) # 将a传入函数f,不会复制a
4557575552
View或者浅复制
不同的数组对象能够共享相同的数据。view
方法创建一个新的数组对象,这个对象与原始数组使用相同的数据。
>>> c = a.view() # c是a的view,或者说c是a的浅复制,c是另一个对象
>>> c is a
False
>>> c.base is a # 确切的说,c是数值的view,数值的属于a
True
>>> c.flags.owndata #所以c的数值并不属于c
False
>>> c.shape = 2,6 # 如果改变c的形状,并不影响a
>>> a.shape
(3, 4)
>>> c[0,4] = 1234 # 但是,如果改变c的数值,a也会受影响
>>> a
array([[ 0, 1, 2, 3],
[1234, 5, 6, 7],
[ 8, 9, 10, 11]])
以上在python中称作view,或者叫浅复制,切片操作就会返回一个view:
>>> s = a[ : , 1:3] # s是a的切片
>>> s[:] = 10 # 改变s的值也会影响a
>>> a
array([[ 0, 10, 10, 3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
深复制
copy
方法生成一个数组的完整备份。
>>> d = a.copy() # 生成一个新的数组对象
>>> d is a
False
>>> d.base is a # d与a不共享任何数值
False
>>> d[0,0] = 9999 #改变d的数值,也不会影响a
>>> a
array([[ 0, 10, 10, 3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
\