我们在以前的文章中已经介绍了如何安装python及其python的一些特性,现在将介绍数据分析过程中经常用到的Numpy库。
NumPy(Numerical Python)是Python语言的一个扩充程序库,支持高级大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用。 这种组合可用于替代 MATLAB.
关于matplotlib可以戳 ➡️
Numpy是一种用于处理数值计算的Python库,运算速度快,提供了一些高度优化的数据结构(如ndarray),是Scikit-learn、Pandas、SciPy等相关库实现某些算法的基础之一。
因为Numpy是个很大的话题,这里仅仅做一个入门介绍,简单介绍一下Numpy的基本的操作。
1# 一维数组:
2import numpy as np
3
4x=[1,2,3,4,5,6,7,8]
5np_arr=np.array(x) # 将python列表变成numpy的ndarray
6
7np_arr
8# array([1, 2, 3, 4, 5, 6, 7, 8])
9np_arr.shape #矩阵维度大小
10# (8,)
11
12# 二维数组:
13
14arr=[[1,2,3],[13,4,6],[33,78,88],[76,88,99]]
15np_2darr= np.array(arr)
16
17type(np_2darr)
18
19# numpy.ndarray
20
21np_2darr
22
23"""
24array([[ 1 2 3]
25 [13 4 6]
26 [33 78 88]
27 [76 88 99]])
28"""
29
30# 查看其维度:
31np_2darr.shape
32# (4, 3) # 4行3列
33
34# 可以将ndarray转换回list:
35np_2darr.tolist()
36# [[1, 2, 3], [13, 4, 6], [33, 78, 88], [76, 88, 99]]
1np.zeros((3,3)) # 创建全为0的二维数组
2np.ones((2,3,4)) # 创建全为1的三维数组
3np.eye(3) # 生成单位矩阵
4np.arange(5) # 生成一维等差数组
5np.arange(6).reshape(2,3) # 生成二维等差数组
6np.linspace(0, 10, num=6) # 生成[0,10]区间的等间隔一维数组
7
8# 生成随机数组:
9np.random.rand(2,3)
10np.random.randint(5, size=(2,3))
NumPy 的主要对象是多维数组 ndarray。在 NumPy 中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。
需要理解清楚ndarray的维度关系,可以参考下图:
ndarray 的索引方式使其更像一个Python容器。Numpy 可以通过切片的方式来提供对ndarray对象的不同观察方式。
1# 索引从0开始,np_arr[0]表示第一个元素,np_arr[-1]表示最后一个元素。
2# 索引左闭右开,np_arr[1:3]表示第二个(如np_arr[1])和第三个元素(np_arr[2]),不包括np_arr[3]
3
4np_2darr[:2] #选取前2行,等效于 np_2darr[:2, :]
5
6"""
7array([[ 1, 2, 3],
8 [13, 4, 6]])
9"""
10np_2darr[:, :2] # 选取前2列
11
12"""
13array([[ 1 2]
14 [13 4]
15 [33 78]
16 [76 88]])
17
18"""
19
20np_2darr[1] # 选取第2行,索引从0开始,0代表第一行
21
22# array([13, 4, 6])
23
24np_2darr[2][0] # 获取第三行第一列
1A = np.array([0, 7, 9])
2
3more_than_3 = A>3
4more_than_3
5# array([False, True, True])
6
7A[more_than_3]
8# array([7, 9])
9
10A[more_than_3]=9999 #赋值
11A
12# array([ 0, 9999, 9999])
Numpy库还提供了处理各种数值计算的操作,如+,-,*,/等
。
但需要理解element-wise和broadcasting,比如:
1# IN:
2a = np.array([[1,2,3],[2,3,4]])
3b= np.array([[1],[10]])
4a/b
5# OUT:
6array([[1. , 2. , 3. ],
7 [0.2, 0.3, 0.4]])
下面重点介绍一下numpy中的乘法运算。
*
对于ndarray,*
运算是element-wise的,必要的时候会进行广播(broadcasting)。比如:
1>>> import numpy as np
2>>> a = np.array(range(6)).reshape((2,3))
3>>> b = np.array([1,0,1])
4
5>>> a
6array([[0, 1, 2],
7 [3, 4, 5]])
8>>> b
9array([1, 0, 1])
10>>> c= a*b
11>>> c
12array([[0, 0, 2],
13 [3, 0, 5]])
14>>> d = a*b.T
15>>> d
16array([[0, 0, 2],
17 [3, 0, 5]])
但是对于matrix,*
遵循矩阵相乘法则,保证维度相对应。
1import numpy as np
2P=np.matrix( [[ 0.11 , 0.06 , 0.25 ],
3 [ 0.04 , 0.4 , 0.31 ],
4 [ 0.07 , 0.07 , 0.11 ],
5 [ 0.1 , 0.1 , 0.15 ],
6 [ 0.01 , 0.4 , 0.4 ],
7 [ 0.005, 0.2 , 0.4 ],
8 [ 0.005, 0.12 , 0.38 ]])
9Q=np.matrix( [[-0.43935806],
10 [-0.83242645],
11 [-0.21580417],
12 [-0.29555744],
13 [-1.00681157],
14 [-0.85996415],
15 [-0.76464043]] )
16P*Q
17
18# 会报错
19# ValueError: shapes (7,3) and (7,1) not aligned: 3 (dim 1) != 7 (dim 0)
np.dot
:对于2-d array,进行矩阵乘法;对于1-d array,进行向量的内积运算。
1>>> a
2array([[0, 1, 2],
3 [3, 4, 5]])
4>>> b
5array([1, 0, 1])
6
7>>> np.dot(a,b)
8# array([2, 8]) # a 2-D数组, b # 1-D数组,不论b是否转置,得到的都得到相同的1-D数组
9
10>>> np.dot(a,b.T)
11# array([2, 8])
但是对于matrix,矩阵相乘就是矩阵相乘,铁板钉钉,所以必须满足矩阵相乘的条件。
1>>> A=np.matrix(a)
2>>> B=np.matrix(b)
3
4>>> np.dot(A,B)
5Traceback (most recent call last):
6 File "<stdin>", line 1, in <module>
7ValueError: objects are not aligned
8
9>>> np.dot(A,B.T)
10matrix([[2],
11 [8]])
*
和 dot
都表示矩阵相乘,必须遵守矩阵相乘法则np.multiply
:multiply
是numpy的函数,执行方法是对应元素相乘,而不是线性代数中的矩阵运算方式,类似于matlab中的点乘,当矩阵的维度不相同时,会根据一定的广播规则将维数扩充到一致的形式。如果不能广播相同的size,multiply
就会失败,举例:
1>>> np.multiply(a,b)
2array([[0, 0, 2],
3 [3, 0, 5]])
4
5>>> np.multiply(a,b.T)
6array([[0, 0, 2],
7 [3, 0, 5]])
8
9>>> np.multiply(A,B)
10matrix([[0, 0, 2],
11 [3, 0, 5]])
12
13>>> np.multiply(A,B.T)
14Traceback (most recent call last):
15 File "<stdin>", line 1, in <module>
16ValueError: operands could not be broadcast together with shapes (2,3) (3,1)
在某些数值计算和代数运算中,可能会需要在输入矩阵的基础上改变结果矩阵的形状,在这方面,Numpy库提供了一下简单有效的方式来重塑和堆叠矩阵。
比如在Keras库中的LSTM模型的输入必须是三维,就要将二维矩阵转变为三维矩阵。
1a=np.random.randn(5)
2a.shape
3# (5,)
4a=a.reshape((5,1))
5b=np.random.randn(5,1)
6b.shape
7# (5,1)
1arr=[[1,2,3],[13,4,6],[33,78,88],[76,88,99]]
2np_2darr= np.array(arr)
3[n_row,n_col] = np_2darr.shape
4np_2darr.reshape(1,n_row*n_col)
1array([[ 1, 2, 3, 13, 4, 6, 33, 78, 88, 76, 88, 99]])
2
3np_2darr.flatten() # 展平
4
5"""
6array([ 1, 2, 3, 13, 4, 6, 33, 78, 88, 76, 88, 99])
7
8"""
np.ravel()
vs np.flatten()
: 1>>> x = np.array([[1, 2], [3, 4]])
2>>> x
3array([[1, 2],
4 [3, 4]])
5>>> x.flatten()
6array([1, 2, 3, 4])
7>>> x.ravel()
8array([1, 2, 3, 4])
9#两者默认均是行序优先
10>>> x.flatten('F')
11array([1, 3, 2, 4])
12>>> x.ravel('F')
13array([1, 3, 2, 4])
14>>> x.reshape(-1)
15array([1, 2, 3, 4])
16>>> x.T.reshape(-1)
17array([1, 3, 2, 4])
1>>> x = np.array([[1, 2], [3, 4]])
2>>> x.flatten()[1] = 100
3>>> x
4array([[1, 2],
5 [3, 4]]) # flatten:返回的是拷贝
6>>> x.ravel()[1] = 100
7>>> x
8array([[ 1, 100],
9 [ 3, 4]])
1B = np.array([[5, 6,8]])
2np.concatenate((np_2darr, B), axis=0)
3
4"""
5array([[ 1, 2, 3],
6 [13, 4, 6],
7 [33, 78, 88],
8 [76, 88, 99],
9 [ 5, 6, 8]])
10"""
在机器学习任务中,经常要将不同列、不同行的数据拼接到一起.
[1] 数组拼接方法一
思路:首先将数组转成列表,然后利用列表的拼接函数append()、extend()等进行拼接处理,最后将列表转成数组。
1# 示例1:
2>>> import numpy as np
3>>> a=np.array([1,2,5])
4>>> b=np.array([10,12,15])
5>>> a_list=list(a)
6>>> b_list=list(b)
7>>> a_list.extend(b_list)
8>>> a_list
9[1, 2, 5, 10, 12, 15]
10>>> a=np.array(a_list)
11>>> a
12array([ 1, 2, 5, 10, 12, 15])
该方法只适用于简单的一维数组拼接,由于转换过程很耗时间,对于大量数据的拼接一般不建议使用。
[2] 数组拼接方法二
思路:numpy提供了np.append(arr, values, axis=None)
函数。对于参数规定,要么一个数组和一个数值;要么两个数组,不能三个及以上数组直接append拼接。append函数返回的始终是一个一维数组。
1# 示例2:
2>>> a=np.arange(5)
3>>> a
4array([0, 1, 2, 3, 4])
5>>> np.append(a,10)
6array([ 0, 1, 2, 3, 4, 10])
7>>> a
8array([0, 1, 2, 3, 4])
9
10>>> b=np.array([11,22,33])
11>>> b
12array([11, 22, 33])
13>>> np.append(a,b)
14array([ 0, 1, 2, 3, 4, 11, 22, 33])
15
16>>> a
17array([[1, 2, 3],
18 [4, 5, 6]])
19>>> b=np.array([[7,8,9],[10,11,12]])
20>>> b
21array([[ 7, 8, 9],
22 [10, 11, 12]])
23>>> np.append(a,b)
24array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
numpy的数组没有动态改变大小的功能,numpy.append()
函数每次都会重新分配整个数组,并把原来的数组复制到新数组中。
[3] 数组拼接方法三
思路:numpy提供了numpy.concatenate((a1,a2,...), axis=0)
函数。能够一次完成多个数组的拼接。其中a1,a2,…是数组类型的参数。
1# 示例3:
2>>> a=np.array([1,2,3])
3>>> b=np.array([11,22,33])
4>>> c=np.array([44,55,66])
5>>> np.concatenate((a,b,c),axis=0) # 默认情况下,axis=0可以不写
6array([ 1, 2, 3, 11, 22, 33, 44, 55, 66]) #对于一维数组拼接,axis的值不影响最后的结果
7
8>>> a=np.array([[1,2,3],[4,5,6]])
9>>> b=np.array([[11,21,31],[7,8,9]])
10>>> np.concatenate((a,b),axis=0)
11array([[ 1, 2, 3],
12 [ 4, 5, 6],
13 [11, 21, 31],
14 [ 7, 8, 9]])
15>>> np.concatenate((a,b),axis=1) #axis=1表示对应行的数组进行拼接
16array([[ 1, 2, 3, 11, 21, 31],
17 [ 4, 5, 6, 7, 8, 9]])
18
19a=np.array([1,2,3]).reshape(-1,1)
20b=np.array([11,22,33]).reshape(-1,1)
21c=np.array([111,222,333]).reshape(-1,1)
22np.concatenate((a,b,c),axis=1)
23"""
24array([[ 1, 11, 111],
25 [ 2, 22, 222],
26 [ 3, 33, 333]])
27"""
对np.append()
和np.concatenate()
两个函数的运行时间进行比较:
1# 示例4:
2>>> from time import clock as now
3>>> a=np.arange(9999)
4>>> b=np.arange(9999)
5>>> time1=now()
6>>> c=np.append(a,b)
7>>> time2=now()
8>>> print time2-time1
928.2316728446
10>>> a=np.arange(9999)
11>>> b=np.arange(9999)
12>>> time1=now()
13>>> c=np.concatenate((a,b),axis=0)
14>>> time2=now()
15>>> print time2-time1
1620.3934997107
可知,np.concatenate()
效率更高,适合大规模的数据拼接。
其次大家也可以使用np.hstack, np.vstack, np.r_, np.c_
等方法来进行ndarray的连接,大家快去探索一下吧!
下一期我们将介绍什么呢?大家期待什么可以给我们留言哦~
numpy官网:http://www.numpy.org/
cs231n-numpy:http://cs231n.github.io/python-numpy-tutorial/