Python数据分析(一)--numpy全知全会
这是python在数据分析和机器学习系列文章的第一篇。
本文全面阐述numpy的方方面面,以供参考。
numpy不仅是数据分析的基础包,也是机器学习进行科学计算的基础。
一、写在前面
导入包
import numpy
#通常的做法是指定一个别名
#下面例子任何地方使用到的np若无特殊说明,一律都是指numpy
import numpy as np
#当然也可以这样导入全部,但是强烈建议不要这样做
from numpy import *
基础属性
numpy的主要对象是多维数组,既然是数组,就必要要有相同的数据类型,同时也可以进行各种计算和操作。关于基础概念,下面以一个例子来详细说明
例子
>>> import numpy as np
>>> n1 = np.array([1,2,3,4],np.int) #一维数组
>>> n1
array([1, 2, 3, 4])
>>> type(n1)
<class 'numpy.ndarray'>
>>> n1.shape #形状,1行4列
(4,)
>>> n1.ndim #维度,这是一维
1
>>> n1.size #元素个数
4
>>> n1.dtype #元素的数据类型
dtype('int32')
>>> n1.itemsize #每个元素的字节大小
4
#为了更好说明以上的属性,以一个多维数组为例就很明显了
>>> n2 = np.arange(24).reshape(3,2,4) #三维数组,arange函数生成的元素值为0到23
>>> n2
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]]])
>>> n2.shape
(3, 2, 4)
>>> n2.ndim
3
>>> n2.dtype
dtype('int32')
>>> n2.size
24
array的创建
通过上面的例子,numpy数组可由常规的List进行创建。此外,numpy也提供了创建特定数组的函数。
例子
>>> n3 = np.zeros([2,3]) #zeros创建全零数组,可指定长度
>>> n3
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> n301 = np.ones([2,3]) #同zeros,ones创建全为1的数组
>>> n301
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
>>> n302 = np.empty((3,3)) #empty创建的数组元素值随机分配,与内存状态有关
>>> n302
array([[ 1.19563886e-321, 0.00000000e+000, 0.00000000e+000],
[ 0.00000000e+000, 0.00000000e+000, 1.08694442e-321],
[ 0.00000000e+000, 0.00000000e+000, 0.00000000e+000]])
#此外,还有zeros_like、ones_like、empty_like函数,参数为一个数组,
#创建出形状与给定数组相同的全零、全一或随机值的数组。
#以zeros_like为例
>>> n4 = np.arange(12).reshape(3,4)
>>> n4
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> np.zeros_like(n4) #形状与n4相同的全零数组
array([[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]])
>>> a = np.arange(1,3,0.5) #指定范围和步长,生成一维数组
>>> a
array([ 1. , 1.5, 2. , 2.5])
>>> np.linspace(1,3,5) #指定范围和元素个数
array([ 1. , 1.5, 2. , 2.5, 3. ])
#随机数组,random中还有诸如randn、random之类的随机函数可生成数组
>>> np.random.rand(3,2)
array([[ 0.27133972, 0.73467037],
[ 0.41100736, 0.75078034],
[ 0.12516107, 0.98181898]])
array的操作
- 一维数组切片比较好理解,对于多维甚至高维数组来说,切片就比较抽象,要指定哪一个轴来切。所以,弄清楚高维数组的轴很重要。
- 将一个数组切分为几个小数组。
- 很多时候需要对数组进行维度变换,比如将一维数组变成三维数组等,或者将高维数组拍扁成低维数组。
- 根据不同的轴将数组进行堆积操作。
- 完全无拷贝、浅拷贝与深拷贝等。下面用一个例子详细了解下。
例子
# 首先看看数组的切片,以三维数组为例
>>> n5 = np.arange(24).reshape(3,2,4)
>>> n5
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]]])
#获取某个特定的值,可以这样
>>> n5[1,1,1]
13
>>> n5[n5%2==0] #选出数组中的偶数
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22])
>>> i = [0,0,1,1,1]
>>> j = [1,1,0,0,0]
>>> k = [1,1,0,0,1]
>>> n5[i,j,k] #i,j,k需要有相同的长度
array([5, 5, 8, 8, 9])
>>> n5[:,:,:] #全切片,只要理解了这种切分方式,就很好理解取得各个维度的数据该怎么写了
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]]])
>>> n5[:,:,1:2] #筛选出第三个维度的第二个数据。注意,第一二维是全部数据
array([[[ 1],
[ 5]],
[[ 9],
[13]],
[[17],
[21]]])
#数组的维度变换,对于上面的三维数组。
>>>n5.reshape(4,6) #转换成四行六列的二维数组,创建一个副本,n5本身没有变
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]])
>>> n5.shape = 4,6 #改变了数组本身的形状
>>> n5
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]])
>>> n5.shape =3,2,-1
>>> n5.shape
(3, 2, 4)
#把一个数组切分为多个较小的数组
>>> n6
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> np.hsplit(n6,2) #相当于把数组切成水平方向的两个小数组
[array([[0, 1],
[4, 5],
[8, 9]]), array([[ 2, 3],
[ 6, 7],
[10, 11]])]
>>> np.hsplit(n6,(1,3)) #指定列前后切
[array([[0],
[4],
[8]]), array([[ 1, 2],
[ 5, 6],
[ 9, 10]]), array([[ 3],
[ 7],
[11]])]
>>> np.vsplit(n6,3)
[array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]
#数组堆积操作。对如下两个2*3的二维数组
>>> a = np.arange(6).reshape(2,3)
>>> b = np.linspace(6,12,6).reshape(2,3)
>>> a
array([[0, 1, 2],
[3, 4, 5]])
>>> b
array([[ 6. , 7.2, 8.4],
[ 9.6, 10.8, 12. ]])
>>> np.vstack((a,b)) #按照行来堆积,可理解为垂直排
array([[ 0. , 1. , 2. ],
[ 3. , 4. , 5. ],
[ 6. , 7.2, 8.4],
[ 9.6, 10.8, 12. ]])
>>> np.hstack((a,b)) #按照列来堆积,可理解为水平方向并排一起
array([[ 0. , 1. , 2. , 6. , 7.2, 8.4],
[ 3. , 4. , 5. , 9.6, 10.8, 12. ]])
#关于数组的拷贝
>>> c = np.arange(2,9)
#d和c是完全相同的数组,存储位置一样
>>> d=c
>>> d is c
True
#e是c的浅拷贝,有相同的元素,一个修改另一个也被修改,但存储的位置不一样
>>> e = c.view()
>>> e
array([2, 3, 4, 5, 6, 7, 8])
>>> e[0] = 333
>>> c
array([333, 3, 4, 5, 6, 7, 8])
>>> e
array([333, 3, 4, 5, 6, 7, 8])
>>> e is c
False
#f是c的深拷贝,修改值相互不影响
>>> f = c.copy()
>>> f
array([333, 3, 4, 5, 6, 7, 8])
>>> f[0]=2
>>> c
array([333, 3, 4, 5, 6, 7, 8])
二、向量和矩阵
numpy在向量和矩阵的运算中扮演着十分重要的角色,不仅提供许多常用的数学和统计函数,并且计算速度也很不错。
基础运算
numpy数组的算术运算是基于元素级别的,并且基于numpy的广播机制,在数据运算中,若维度不一致也能进行运算。numpy支持的算术运算很多,就不一一列举了。
例子
>>> a
array([[1, 2, 3, 4],
[2, 3, 4, 3]])
>>> b
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
>>> c
array([5, 6, 4, 7])
>>> a+b #元素对应相加
array([[ 1, 3, 5, 7],
[ 6, 8, 10, 10]])
>>> a+c #即使c只有一维,也会广播到a的每一维进行计算
array([[ 6, 8, 7, 11],
[ 7, 9, 8, 10]])
向量与矩阵的运算
标量、向量与矩阵之间相互的运算,在numpy中实现起来十分简单,比如常见的点积(內积)、外积和叉乘。下面以两个矩阵a、b和两个向量c、d展示一下numpy在这些运算中的实现。
例子
>>> a #2*4的矩阵
array([[1, 2, 3, 4],
[2, 3, 4, 3]])
>>> b #2*4的矩阵
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
>>> c #向量
array([5, 6, 4, 7])
>>> d = np.arange(2,6)
>>> d #向量
array([2, 3, 4, 5])
>>> np.dot(c,d) #向量的內积是个标量
79
>>> np.dot(a,b.T) #矩阵的点积,这里将b转置成4*2的矩阵(若使用np.inner便不需要将b转置)
array([[20, 60],
[20, 68]])
>>> np.dot(a,c) #矩阵和向量的点积
array([57, 65])
>>> np.outer(c,d) #向量的外积
array([[10, 15, 20, 25],
[12, 18, 24, 30],
[ 8, 12, 16, 20],
[14, 21, 28, 35]])
>>> np.outer(a,b) #矩阵的外积
array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 0, 2, 4, 6, 8, 10, 12, 14],
[ 0, 3, 6, 9, 12, 15, 18, 21],
[ 0, 4, 8, 12, 16, 20, 24, 28],
[ 0, 2, 4, 6, 8, 10, 12, 14],
[ 0, 3, 6, 9, 12, 15, 18, 21],
[ 0, 4, 8, 12, 16, 20, 24, 28],
对于矩阵,np.linalg中提供了矩阵的各种运算包括转置、矩阵求逆等等。
例子 矩阵操作
#矩阵的转置,直接在矩阵后面接个.T,如上的矩阵b
>>> b.T #与 b.transpose()是等价的
array([[0, 4],
[1, 5],
[2, 6],
[3, 7]])
#同时也可以对多维数组进行转置操作
>>> np.arange(12).reshape(2,2,3)
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]])
>>> np.arange(12).reshape(2,2,3).T #2*2*3变成了3*2*2
array([[[ 0, 6],
[ 3, 9]],
[[ 1, 7],
[ 4, 10]],
[[ 2, 8],
[ 5, 11]]])
#为了便于计算,给定一个方阵i
>>> i = np.arange(9).reshape(3,3)
>>> i
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> np.trace(i) #矩阵的迹,即对角线上元素之和
12
#使用 np.linalg 的eig计算出矩阵的特征值和特征向量
>>> t1,tv = np.linalg.eig(i)
>>> t1 #特征值
array([ 1.33484692e+01, -1.34846923e+00, -2.48477279e-16])
>>> tv #特征向量
array([[ 0.16476382, 0.79969966, 0.40824829],
[ 0.50577448, 0.10420579, -0.81649658],
[ 0.84678513, -0.59128809, 0.40824829]])
#上面挖了个坑,这里构造一个可逆的矩阵j
>>> j = np.array([[3,1,4],[3,3,5],[1,7,1]])
>>> j
array([[3, 1, 4],
[3, 3, 5],
[1, 7, 1]])
>>> np.linalg.det(j) #求矩阵的行列式
-22.000000000000004
>>> np.linalg.inv(j) #求矩阵的逆矩阵
array([[ 1.45454545, -1.22727273, 0.31818182],
[-0.09090909, 0.04545455, 0.13636364],
[-0.81818182, 0.90909091, -0.27272727]])
#对一个3*4的矩阵进行奇异值分解
>>> u,s,v = np.linalg.svd(np.arange(12).reshape(3,4))
>>> u
array([[-0.1473065 , -0.90090739, 0.40824829],
[-0.50027528, -0.2881978 , -0.81649658],
[-0.85324407, 0.32451178, 0.40824829]])
>>> s
array([ 2.24092982e+01, 1.95534034e+00, 7.68985043e-16])
>>> v
array([[-0.39390139, -0.46087474, -0.5278481 , -0.59482145],
[ 0.73813393, 0.29596363, -0.14620666, -0.58837696],
[-0.50775138, 0.52390687, 0.47544042, -0.4915959 ],
[-0.20539847, 0.65232016, -0.68844492, 0.24152322]])
除此之外,linalg模块中还有许多操作,如:
- norm Vector or matrix norm - inv Inverse of a square matrix - solve Solve a linear system of equations - det Determinant of a square matrix - lstsq Solve linear least-squares problem - pinv Pseudo-inverse (Moore-Penrose) calculated using a singular value decomposition - eig Eigenvalues and vectors of a square matrix - eigh Eigenvalues and eigenvectors of a Hermitian matrix - eigvals Eigenvalues of a square matrix - eigvalsh Eigenvalues of a Hermitian matrix - qr QR decomposition of a matrix - svd Singular value decomposition of a matrix - cholesky Cholesky decomposition of a matrix - tensorsolve Solve a linear tensor equation - tensorinv Calculate an inverse of a tensor
三、常用数学函数
numpy中包括丰富的数学函数和统计函数,比如三角函数、统计学上的均值、方差、标准差、相关系数等。
基本数学函数
如常见的求和、最小/最大值等(对于多维数组,可指定对哪个轴进行计算)。下面以三维数组n5求和为例说明一下关于轴的选择。
例子
>>> n5 #这是一个3*2*4的数组
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]]])
#对第一个轴求和,即相当于对第一维(长度为3)进行计算,得到的是2*4的数组
#24=0+8+16,以此类推
>>> np.sum(n5,axis=0)
array([[24, 27, 30, 33],
[36, 39, 42, 45]])
#对第二个轴求和,即相当于对第二维(长度为2)进行计算,得到的是3*4的数组
#4=0+4,以此类推
>>> np.sum(n5,axis=1)
array([[ 4, 6, 8, 10],
[20, 22, 24, 26],
[36, 38, 40, 42]])
#对第三个轴求和,即相当于对第三维(长度为4)进行计算,得到的是3*2的数组
#6=0+1+2+3,以此类推
>>> np.sum(n5,axis=2)
array([[ 6, 22],
[38, 54],
[70, 86]])
>>> np.sum(n5) #所有元素的和
276
三角函数
在numpy中使用三角函数也很方便,比如正弦np.sin;相应的,余弦:cos,正切:tan,以及反函数arcsin、arccos和arctan。还有一些诸如双曲函数,sinh、cosh、tanh等等。
例子
>>> np.sin(np.pi/2) #计算pi的正弦值为1
1.0
#计算并画出0到2*pi的正弦函数曲线
>>> e = np.arange(0,2*np.pi,0.1)
>>> import matplotlib.pyplot as plt
>>> plt.plot(e,np.sin(e))
[<matplotlib.lines.Line2D object at 0x0000000004D54C18>]
>>> plt.show() #结果如图
[图片上传失败...(image-1d6edc-1544870342615)]
统计函数
比较常见的有均值(mean)、标准差(std)、方差(var)、中位数(median)、协方差(cov)、相关系数(corrcoef)等。同样对于多维数组,也可以指定根据哪个轴进行计算。
>>> n5
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]]])
>>> np.std(n5)
6.9221865524317288
>>> np.std(n5,axis=0)
array([[ 6.53197265, 6.53197265, 6.53197265, 6.53197265],
[ 6.53197265, 6.53197265, 6.53197265, 6.53197265]])
小例子
使用numpy计算一个sigmoid函数的值并画出函数图像。
>>> def sigmoid(x):
... return 1.0/(1+np.e**(-x))
...
>>> x = np.arange(-5,5,0.01)
>>> plt.plot(x,sigmoid(x))
[<matplotlib.lines.Line2D object at 0x0000000008287AC8>]
>>> plt.show() #如图
sigmoid函数
结语
以上就是笔者工作中常用到的功能,特此记录下来,便于以后查阅,如果能够帮到需要的人再好不过了。虽然希望也尽力能够全方位解析numpy在数据分析和科学计算上面的魅力,怎奈时间精力和个人知识经验有限,实在不可能面面俱到,如果有欠缺的地方还望参考其他更多资料,如果能够留言给予提醒那就再感激不过了。