Numpy是一个开源的Python科学计算库,它是python科学计算库的基础库,许多其余著名的科学计算库如Pandas,Scikit-learn等都要用到Numpy库的一些功能。vue
本文主要内容以下:python
Numpy中的多维数组称为ndarray,这是Numpy中最多见的数组对象。ndarray对象一般包含两个部分:npm
Numpy数组的优点数组
关于向量化和标量化运算,对比下面的参考例子就能够看出差别微信
def pySum():
a = list(range(10000))
b = list(range(10000))
c = []
for i in range(len(a)):
c.append(a[i]**2 + b[i]**2)
return c
%timeit pySum()
10 loops, best of 3: 49.4 ms per loop
import numpy as np
def npSum():
a = np.arange(10000)
b = np.arange(10000)
c = a**2 + b**2
return c
%timeit npSum()
The slowest run took 262.56 times longer than the fastest. This could mean that an intermediate result is being cached. 1000 loops, best of 3: 128 µs per loop
从上面的运行结果能够看出,numpy的向量化运算的效率要远远高于python的循环遍历运算(效率相差好几百倍)。
(1ms=1000µs)markdown
首先须要导入numpy库,在导入numpy库时一般使用“np”做为简写,这也是Numpy官方倡导的写法。app
固然,你也能够选择其余简写的方式或者直接写numpy,但仍是建议用“np”,这样你的程序能和大都数人的程序保持一致。dom
import numpy as np
建立ndarray数组的方式有不少种,这里介绍我使用的较多的几种:函数
Method 1: 基于list或tupleoop
# 一维数组
# 基于list
arr1 = np.array([1,2,3,4])
print(arr1)
# 基于tuple
arr_tuple = np.array((1,2,3,4))
print(arr_tuple)
# 二维数组 (2*3)
arr2 = np.array([[1,2,4], [3,4,5]])
arr2
[1 2 3 4] [1 2 3 4] array([[1, 2, 4], [3, 4, 5]])
请注意:
Method 2: 基于np.arange
# 一维数组
arr1 = np.arange(5)
print(arr1)
# 二维数组
arr2 = np.array([np.arange(3), np.arange(3)])
arr2
[0 1 2 3 4] array([[0, 1, 2], [0, 1, 2]])
Method 3: 基于arange以及reshape建立多维数组
# 建立三维数组
arr = np.arange(24).reshape(2,3,4)
arr
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]]])
请注意:arange的长度与ndarray的维度的乘积要相等,即 24 = 2X3X4
Numpy的数值类型以下:
每一种数据类型都有相应的数据转换函数,参考示例以下:
np.int8(12.334)
12
np.float64(12)
12.0
np.float(True)
1.0
bool(1)
True
在建立ndarray数组时,能够指定数值类型:
a = np.arange(5, dtype=float)
a
array([ 0., 1., 2., 3., 4.])
请注意,复数不能转换成为整数类型或者浮点数,好比下面的代码会运行出错
# float(42 + 1j)
np.arange(4, dtype=float)
array([ 0., 1., 2., 3.])
# 'D'表示复数类型
np.arange(4, dtype='D')
array([ 0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j])
np.array([1.22,3.45,6.779], dtype='int8')
array([1, 3, 6], dtype=int8)
a = np.array([[1,2,3], [7,8,9]])
a.ndim
2
a.shape
(2, 3)
a.size
6
a.itemsize
4
a.nbytes
24
a.size*a.itemsize
24
b = np.arange(24).reshape(4,6)
b
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]])
b.T
array([[ 0, 6, 12, 18], [ 1, 7, 13, 19], [ 2, 8, 14, 20], [ 3, 9, 15, 21], [ 4, 10, 16, 22], [ 5, 11, 17, 23]])
d = np.array([1.2+2j, 2+3j])
d
array([ 1.2+2.j, 2.0+3.j])
real属性返回数组的实部
d.real
array([ 1.2, 2. ])
imag属性返回数组的虚部
d.imag
array([ 2., 3.])
e = np.arange(6).reshape(2,3)
e
array([[0, 1, 2], [3, 4, 5]])
f = e.flat f
<numpy.flatiter at 0x65eaca0>
for item in f:
print(item)
0 1 2 3 4 5
可经过位置进行索引,以下:
f[2]
2
f[[1,4]]
array([1, 4])
也能够进行赋值
e.flat=7
e
array([[7, 7, 7], [7, 7, 7]])
e.flat[[1,4]]=1
e
array([[7, 1, 7], [7, 1, 7]])
下图是对ndarray各类属性的一个小结
一维数组的切片和索引与python的list索引相似。
a = np.arange(7)
a
array([0, 1, 2, 3, 4, 5, 6])
a[1:4]
array([1, 2, 3])
# 每间隔2个取一个数
a[ : 6: 2]
array([0, 2, 4])
二维数组的切片和索引,以下所示:
插播一条硬广:技术文章转发太多。本文涉及的代码量比较多,如须要查看源代码,请在微信公众号“Python数据之道”(ID:PyDataRoad)后台回复关键字“2017026”。
b.reshape(4,3)
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
b
array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
b.resize(4,3)
b
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
函数resize()的做用跟reshape()相似,可是会改变所做用的数组,至关于有inplace=True的效果
b.ravel()
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
b.flatten()
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
b
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
二者的区别在于返回拷贝(copy)仍是返回视图(view),flatten()返回一份拷贝,须要分配新的内存空间,对拷贝所作的修改不会影响原始矩阵,而ravel()返回的是视图(view),会影响原始矩阵。
参考以下代码:
b.shape=(2,6)
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
前面描述了数组转置的属性(T),也能够经过transpose()函数来实现
b.transpose()
array([[ 0, 6], [ 1, 7], [20, 8], [ 3, 9], [ 4, 10], [ 5, 11]])
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
c = b*2
c
array([[ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
hstack()
np.hstack((b,c))
array([[ 0, 1, 20, 3, 4, 5, 0, 2, 40, 6, 8, 10], [ 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22]])
column_stack()函数以列方式对数组进行叠加,功能相似hstack()
np.column_stack((b,c))
array([[ 0, 1, 20, 3, 4, 5, 0, 2, 40, 6, 8, 10], [ 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22]])
vstack()
np.vstack((b,c))
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
row_stack()函数以行方式对数组进行叠加,功能相似vstack()
np.row_stack((b,c))
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
axis=1时,沿水平方向叠加
axis=0时,沿垂直方向叠加
np.concatenate((b,c),axis=1)
array([[ 0, 1, 20, 3, 4, 5, 0, 2, 40, 6, 8, 10], [ 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22]])
np.concatenate((b,c),axis=0)
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
因为针对数组的轴为0或1的方向常常会混淆,经过示意图,或许能够更好的理解。
关于数组的轴方向示意图,以及叠加的示意图,以下:
深度叠加
这个有点烧脑,举个例子以下,本身能够体会下:
arr_dstack = np.dstack((b,c)) print(arr_dstack.shape) arr_dstack
(2, 6, 2) array([[[ 0, 0], [ 1, 2], [20, 40], [ 3, 6], [ 4, 8], [ 5, 10]], [[ 6, 12], [ 7, 14], [ 8, 16], [ 9, 18], [10, 20], [11, 22]]])
叠加前,b和c均是shape为(2,6)的二维数组,叠加后,arr_dstack是shape为(2,6,2)的三维数组。
深度叠加的示意图以下:
跟数组的叠加相似,数组的拆分能够分为横向拆分、纵向拆分以及深度拆分。
涉及的函数为 hsplit()、vsplit()、dsplit() 以及split()
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
np.hsplit(b, 2)
[array([[ 0, 1, 20], [ 6, 7, 8]]), array([[ 3, 4, 5], [ 9, 10, 11]])]
np.split(b,2, axis=1)
[array([[ 0, 1, 20], [ 6, 7, 8]]), array([[ 3, 4, 5], [ 9, 10, 11]])]
np.vsplit(b, 2)
[array([[ 0, 1, 20, 3, 4, 5]]), array([[ 6, 7, 8, 9, 10, 11]])]
np.split(b,2,axis=0)
[array([[ 0, 1, 20, 3, 4, 5]]), array([[ 6, 7, 8, 9, 10, 11]])]
arr_dstack
array([[[ 0, 0], [ 1, 2], [20, 40], [ 3, 6], [ 4, 8], [ 5, 10]], [[ 6, 12], [ 7, 14], [ 8, 16], [ 9, 18], [10, 20], [11, 22]]])
np.dsplit(arr_dstack,2)
[array([[[ 0], [ 1], [20], [ 3], [ 4], [ 5]], [[ 6], [ 7], [ 8], [ 9], [10], [11]]]), array([[[ 0], [ 2], [40], [ 6], [ 8], [10]], [[12], [14], [16], [18], [20], [22]]])]
拆分的结果是原来的三维数组拆分红为两个二维数组。
这个烧脑的拆分过程能够自行分析下~~
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
b.tolist()
[[0, 1, 20, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
b.astype(float)
array([[ 0., 1., 20., 3., 4., 5.], [ 6., 7., 8., 9., 10., 11.]])
经常使用的函数以下:
请注意函数在使用时须要指定axis轴的方向,若不指定,默认统计整个数组。
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
np.max(b)
20
# 沿axis=1轴方向统计
np.max(b,axis=1)
array([20, 11])
# 沿axis=0轴方向统计
np.max(b,axis=0)
array([ 6, 7, 20, 9, 10, 11])
np.min(b)
0
np.ptp(b)
20
# 沿axis=0轴方向
np.ptp(b, axis=0)
array([ 6, 6, 12, 6, 6, 6])
# 沿axis=1轴方向
np.ptp(b, axis=1)
array([20, 5])
b.resize(4,3)
b
array([[ 0, 1, 20], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
np.cumsum(b, axis=1)
array([[ 0, 1, 21], [ 3, 7, 12], [ 6, 13, 21], [ 9, 19, 30]], dtype=int32)
np.cumsum(b, axis=0)
array([[ 0, 1, 20], [ 3, 5, 25], [ 9, 12, 33], [18, 22, 44]], dtype=int32)
np.cumprod(b,axis=1)
array([[ 0, 0, 0], [ 3, 12, 60], [ 6, 42, 336], [ 9, 90, 990]], dtype=int32)
np.cumprod(b,axis=0)
array([[ 0, 1, 20], [ 0, 4, 100], [ 0, 28, 800], [ 0, 280, 8800]], dtype=int32)
当数组跟一个标量进行数学运算时,标量须要根据数组的形状进行扩展,而后执行运算。
这个扩展的过程称为“广播(broadcasting)”
b
array([[ 0, 1, 20], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
d = b + 2
d
array([[ 2, 3, 22], [ 5, 6, 7], [ 8, 9, 10], [11, 12, 13]])
numpy涵盖的内容实际上是很是丰富的,本文仅仅介绍了numpy一些经常使用的基本功能,算是对numpy的一个入门级的简单的较为全面的描述。
numpy官方的《Numpy Reference》文档,光页面数量就有1500+页,如想要系统的学习numpy,建议仔细阅读官方的参考文档,可在其官方网站进行查阅。固然,资料都是英文版的,可能看起来难度稍微大点,看习惯了就好。
本文涉及的代码量比较多,如须要查看源代码,请在微信公众号“Python数据之道”(ID:PyDataRoad)后台回复关键字“2017026”。