Python有许多吸引力,如效率、代码可读性和速度,使其成为数据科学爱好者的首选编程语言。它拥有大量的库,使数据科学家可以更轻松地完成复杂的任务,而无须编写很多代码。本节将对数据科学的前三个Python库进行介绍。
NumPy(Numerical Python)是Python语言的一个扩展程序库,支持大量的维度数组与矩阵运算,它是一个运行速度非常快的数学库,主要用于数组计算。
NumPy最重要的一个特点是其 N 维数组对象ndarray,它是一系列同类型数据的集合,以0下标为开始进行集合中元素的索引。ndarray对象是用于存放同类型元素的多维数组。每个元素在内存中都有相同存储大小的区域。
ndarray内部由以下内容组成。
· 一个指向数据(内存或内存映射文件中的数据)的指针。
· 数据类型(dtype),描述在数组中的固定大小值的格子。
· 一个表示数组形状(shape)的元组,表示各维度大小的元组。
· 一个跨度(stride)元组,其中的整数指的是为了前进到当前维度下一个元素需要“跨过”的字节数。
【例1-6】 创建一个二维度的ndarray对象。
#多于一个维度 import numpy as np a=np.array([[1,7],[3,5]]) print(a)
运行程序,输出如下:
[[1 7] [3 5]]
数据类型对象(numpy.dtype类的实例)用来描述与数组对应的内存区域是如何使用的,字节顺序是通过对数据类型预先设定<或>来决定的。<为小端法,最小值存储在最小的地址,即低位组放在最前面;>为大端法,最重要的字节存储在最小的地址,即高位组放在最前面。
dtype对象的语法构造如下:
numpy.dtype(object,align,copy)
· object:要转换为的数据类型对象。
· align:如果为True,则是填充字段使其类似C的结构体。
· copy:复制dtype对象,如果为False,则是对内置数据类型对象的引用。
【例1-7】 定义一个结构化数据类型student,包含字符串字段name、整数字段age及浮点数字段marks,并将这个dtype应用到ndarray对象。
import numpy as np student=np.dtype([('name','S18'),('age','i1'),('marks','f4')]) print(student)
运行程序,输出如下:
[('name','S18'),('age','i1'),('marks','<f4')]
NumPy数组的维数称为秩(rank),秩就是轴的数量,即数组的维度。一维数组的秩为1,二维数组的秩为2,以此类推。
在NumPy中,每一个线性的数组称为一个轴(axis),也就是维度(dimension)。例如,二维数组相当于两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是NumPy中的轴,第一个轴相当于底层数组,第二个轴相当于底层数组里的数组。而轴的数量——秩,就是数组的维数。
很多时候可以声明axis,axis=0表示沿着第0轴进行操作,即对每一列进行操作;axis=1表示沿着1轴进行操作,即对每一行进行操作。NumPy的数组中比较重要的ndarray对象属性如表1-1所示。
表1-1 ndarray对象属性
【例1-8】 利用reshape改变数组的形状。
import numpy as np c1=np.arange(12) #生成一个有12个数据的一维数组 print('有12个数据的一维数组:',c1) print("=" * 20) c2=c1.reshape((3,4)) #变成一个二维数组,是3行4列的 print('3行4列数组:',c2) print("=" * 20) c3=c1.reshape((2,3,2)) #变成一个三维数组,总共有两块(第一个参数),每一块都是2行2 #列的(三维数组中数的数量要和一维数组中数的数量要一致) print('三维数组:',c3) print("=" * 20) c4=c2.reshape((12,)) #将ac的二维数组重新变成一个12列的一维数组 print('重新变成一个12列的一维数组:',c4) print("=" * 20) c5=c2.flatten() #无论c2是几维数组,都将它变成一个一维数组 print('变成一个一维数组:',c5) print("=" * 20) c6=c3.flatten() #无论c3是几维数组,都将它变成一个一维数组 print('变成一个一维数组:',c6)
运行程序,输出如下:
有12个数据的一维数组:[0 1 2 3 4 5 6 7 8 9 10 11] ==================== 3行4列数组:[[0 1 2 3] [4 5 6 7] [8 9 10 11]] ==================== 三维数组:[[[0 1] [2 3] [4 5]] [[6 7] [8 9] [10 11]]] ==================== 重新变成一个12列的一维数组:[0 1 2 3 4 5 6 7 8 9 10 11] ==================== 变成一个一维数组:[0 1 2 3 4 5 6 7 8 9 10 11] ==================== 变成一个一维数组:[0 1 2 3 4 5 6 7 8 9 10 11]
ndarray数组除了可以使用底层ndarray构造器来创建外,也可以通过以下几种方式来创建。
1)numpy.empty
numpy.empty用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组。其语法格式如下:
numpy.empty(shape,dtype=float,order= 'C')
其中,shape为数组形状;dtype为数据类型,可选;order为在计算机内存中的存储元素的顺序,有C和F两个选项,分别代表行优先和列优先。
2)numpy.zeros
numpy.zeros用于创建指定大小的数组,数组元素以0来填充。其语法格式如下:
numpy.zeros(shape,dtype=float,order= 'C')
其中,shape为数组形状;dtype为数据类型,可选;order有C和F两个选项,C用于C的行数组,F用于FORTRAN的列数组。
numpy.ones创建指定形状的数组,数组元素以1来填充,参数含义与numpy.zeros一样。
3)从已有的数组创建数组
在NumPy中从已有的数组创建数组有三种方法,分别为numpy.asarray、numpy.frombuffer及numpy.fromiter。
(1)numpy.asarray方法。
numpy.asarray类似numpy.array,但numpy.asarray参数只有三个,比numpy.array少两个。其语法格式如下:
numpy.asarray(a,dtype=None,order=None)
其中,a为任意形式的输入参数,可以是列表、列表的元组、元组、元组的元组、元组的列表、多维数组;dtype为数据类型,可选;order可选,用于确定在计算机内存中存储元素的顺序,有C和F两个选项,分别代表行优先和列优先。
【例1-9】 利用numpy.asarray方法从已有的数组中创建数组。
import numpy as np #将列表转换为ndarray x1=[1,2,3] a1=np.asarray(x1) print('将列表转换为ndarray:',a1) #将元组转换为ndarray x2=(1,2,3) a2=np.asarray(x2) print('将元组转换为ndarray:',a2) #将元组列表转换为ndarray x3=[(1,2,3),(4,5)] a3=np.asarray(x3) print('将元组列表转换为ndarray:',a3) #设置了dtype参数 a4=np.asarray(x1,dtype=float) print('设置了dtype参数:',a4)
运行程序,输出如下:
将列表转换为ndarray:[1 2 3] 将元组转换为ndarray:[1 2 3] 将元组列表转换为ndarray:[(1,2,3)(4,5)] 设置了dtype参数:[1.2.3.]
(2)numpy.frombuffer方法。
numpy.frombuffer用于实现动态数组,它接收buffer输入参数,以流的形式读入,转换为ndarray对象。其语法格式如下:
numpy.frombuffer(buffer,dtype=float,count=-1,offset=0)
其中,buffer可以是任意对象,会以流的形式读入;dtype为返回数组的数据类型,可选;count为读取的数据数量,默认为-1,表示读取所有数据;offset为读取的起始位置,默认为0。
注意,buffer是字符串时,Python 3默认str是Unicode类型,所以要转换为bytestring,在原str前加上b。
【例1-10】 使用numpy.frombuffer方法创建数组。
import numpy as np s=b'HelloWorld' a=np.frombuffer(s,dtype= 'S1') print(a)
运行程序,输出如下:
[b'H'b'e'b'l'b'l'b'o'b''b'W'b'o'b'r'b'l'b'd']
(3)numpy.fromiter方法。
numpy.fromiter方法从可迭代对象中建立ndarray对象,返回一维数组。其语法格式如下:
numpy.fromiter(iterable,dtype,count=-1)
其中,iterable为可迭代对象;dtype返回数组的数据类型;count为读取的数据数量,默认为-1,表示读取所有数据。
【例1-11】 利用numpy.fromiter方法创建数组。
import numpy as np #使用range函数创建列表对象 list=range(5) it=iter(list) #使用迭代器创建ndarray x=np.fromiter(it,dtype=float) print(x)
运行程序,输出如下:
[0.1.2.3.4.]
4)使用NumPy从数值范围创建数组
本小节将学习如何从数值范围创建数组。
(1)numpy.arange。
numpy.arange函数创建数值范围并返回ndarray对象。其语法格式如下:
numpy.arange(start,stop,step,dtype)
表示根据start与stop指定的范围及step设定的步长,生成一个ndarray。
(2)numpy.linspace。
numpy.linspace函数用于创建一个一维数组,数组由一个等差数列构成。其语法格式如下:
np.linspace(start,stop,num=50,endpoint=True,retstep=False,dtype=None)
其中,start为序列的起始值;stop为序列的终止值;num为要生成的等步长的样本数量,默认为50;endpoint为True时,数列中包含stop值,反之不包含,默认为True;retstep为True时,生成的数组中会显示间距,反之不显示;dtype为数据类型ndarray。
(3)numpy.logspace。
numpy.logspace函数用于创建一个等比数列。其语法格式如下:
np.logspace(start,stop,num=50,endpoint=True,base=10.0,dtype=None)
其中,start序列的起始值为base×start;stop序列的终止值为base×stop,如果endpoint为True,则该值包含于数列中;num为要生成的等步长的样本数量,默认为50;endpoint的值为True时,数列中包含stop值,反之不包含,默认为True。
【例1-12】 创建数值范围的数组。
#生成0到4长度为5的数组 import numpy as np x=np.arange(5) print('生成0到4长度为5的数组:',x) #设置起始点为1,终止等差点为10,数列个数为10 a=np.linspace(1,10,10) print('创建等差数组:',a) #创建对数的底数为2的等比数组 a=np.logspace(0,9,10,base=2) print('创建底数为2的等比数组:',a)
运行程序,输出如下:
生成0到4长度为5的数组:[0 1 2 3 4] 创建等差数组:[1. 2. 3. 4. 5. 6. 7. 8. 9.10.] 创建底数为2的等比数组:[1. 2. 4. 8. 16. 32. 64.128.256.512.]
NumPy中包含了一些函数用于处理数组,可以分为修改数组形状、翻转数组、修改数组维度、连接数组、分割数组及数组元素的添加与删除等。
下面直接通过实例来演示。
【例1-13】 数组操作实例。
import numpy as np #numpy.reshape改变数组形状 a=np.arange(8) print('原始数组:',a) b=a.reshape(4,2) print('修改后的数组:',b)
运行程序,输出如下:
原始数组:[0 1 2 3 4 5 6 7] 修改后的数组:[[0 1] [2 3] [4 5] [6 7]] #numpy.ravel实现数组变形 a=np.arange(8).reshape(2,4) print('原数组:',a) print('调用ravel函数之后:',a.ravel()) print('以F风格顺序调用ravel函数之后:',a.ravel(order= 'F'))
运行程序,输出如下:
原数组:[[0 1 2 3] [4 5 6 7]] 调用ravel函数之后:[0 1 2 3 4 5 6 7] 以F风格顺序调用ravel函数之后:[0 4 1 5 2 6 3 7] #numpy.transpose对数组实现对换 a=np.arange(12).reshape(3,4) print('原数组:',a) print('对换数组:',np.transpose(a))
运行程序,输出如下:
原数组:[[0 1 2 3] [4 5 6 7] [8 9 10 11]] 对换数组:[[0 4 8] [1 5 9] [2 6 10] [3 7 11]] #创建了三维的ndarray a=np.arange(8).reshape(2,2,2) print('原数组:',a) #现在交换轴0(深度方向)到轴2(宽度方向) print('调用swapaxes函数后的数组:',np.swapaxes(a,2,0))
运行程序,输出如下:
原数组:[[[0 1] [2 3]] [[4 5] [6 7]]] 调用swapaxes函数后的数组:[[[0 4] [2 6]] [[1 5] [3 7]]] #numpy.concatenate连接数组 a=np.array([[1,2],[3,4]]) print('第一个数组:',a) b=np.array([[5,6],[7,8]]) print('第二个数组:',b) #两个数组的维度相同 print('沿轴0连接两个数组:',np.concatenate((a,b))) print('沿轴1连接两个数组:',np.concatenate((a,b),axis=1))
运行程序,输出如下:
第一个数组:[[1 2] [3 4]] 第二个数组:[[5 6] [7 8]] 沿轴0连接两个数组:[[1 2] [3 4] [5 6] [7 8]] 沿轴1连接两个数组:[[1 2 5 6] [3 4 7 8]] #axis为0时在水平方向分割,axis为1时在垂直方向分割 a=np.arange(16).reshape(4,4) print('第一个数组:',a) b=np.split(a,2) print('默认分割(0轴):',b) c=np.split(a,2,1) print('沿水平方向分割:',c) d=np.hsplit(a,2) print('沿水平方向分割:',d)
运行程序,输出如下:
第一个数组:[[0 1 2 3] [4 5 6 7] [8 9 10 11] [12 13 14 15]] 默认分割(0轴):[array([[0,1,2,3], [4,5,6,7]]),array([[8,9,10,11], [12,13,14,15]])] 沿水平方向分割:[array([[0,1], [4,5], [8,9], [12,13]]),array([[2,3], [6,7], [10,11], [14,15]])] 沿水平方向分割:[array([[0,1], [4,5], [8,9], [12,13]]),array([[2,3], [6,7], [10,11], [14,15]])]
NumPy算术函数包含简单的加、减、乘、除,对应函数分别为add、subtract、multiply和divide。
需要注意的是,数组必须具有相同的形状或符合数组广播规则。
【例1-14】 数组的简单加、减、乘、除运算。
import numpy as np a=np.arange(9,dtype=np.float_).reshape(3,3) print('第一个数组:',a) b=np.array([10,10,10]) print('第二个数组:',b) print('两个数组相加:',np.add(a,b)) print('两个数组相减:',np.subtract(a,b)) print('两个数组相乘:',np.multiply(a,b)) print('两个数组相除:',np.divide(a,b))
运行程序,输出如下:
第一个数组:[[0.1.2.] [3.4.5.] [6.7.8.]] 第二个数组:[10 10 10] 两个数组相加:[[10.11.12.] [13.14.15.] [16.17.18.]] 两个数组相减:[[-10.-9.-8.] [-7.-6.-5.] [-4.-3.-2.]] 两个数组相乘:[[0.10.20.] [30.40.50.] [60.70.80.]] 两个数组相除:[[0.0.1 0.2] [0.3 0.4 0.5] [0.6 0.7 0.8]]
此外NumPy也包含了其他重要的算术函数。
(1)numpy.reciprocal:函数返回参数逐元素的倒数。如1/4的倒数为4/1。
(2)numpy.power:函数将第一个输入数组中的元素作为底数,计算它与第二个输入数组中相应元素的幂。
(3)numpy.mod:计算输入数组中相应元素相除后的余数。此外,函数numpy.remainder也产生相同的结果。
【例1-15】 其他算术运算函数。
import numpy as np a1=np.array([0.25,1.43,1,101]) print('数组是:',a1) print('调用reciprocal函数:',np.reciprocal(a1)) a2=np.array([10,100,1000])
运行程序,输出如下:
数组是:[0.25 1.43 1.101.] 调用reciprocal函数:[4. 0.6993007 1. 0.00990099] print('数组是:',a2) print('调用power函数:',np.power(a2,2)) b2=np.array([1,4,7]) print('第二个数组:',b2) print('再次调用power函数:',np.power(a,b))
运行程序,输出如下:
数组是:[ 10 100 1000] 调用power函数:[ 100 10000 1000000] 第二个数组:[1 4 7] 再次调用power函数:[[0.00000000e+00 1.00000000e+00 1.02400000e+03] [5.90490000e+04 1.04857600e+06 9.76562500e+06] [6.04661760e+07 2.82475249e+08 1.07374182e+09]] a3=np.array([11,22,33]) b3=np.array([3,6,9]) print('第一个数组:',a3) print('第二个数组:',b3) print('调用mod函数:',np.mod(a,b)) print('调用remainder函数:',np.remainder(a,b))
运行程序,输出如下:
第一个数组:[11 22 33] 第二个数组:[3 6 9] 调用mod函数:[[0.1.2.] [3.4.5.] [6.7.8.]] 调用remainder函数:[[0.1.2.] [3.4.5.] [6.7.8.]]
SciPy是一个开源的Python算法库和数学工具包。它是基于NumPy的科学计算库,用于数学、科学、工程学等领域,很多高阶抽象和物理模型都需要使用SciPy。
SciPy常量模块constants提供了许多内置的数学常数。圆周率是一个数学常数,为一个圆的周长和其直径的比率,近似值约等于3.141 59,常用符号π来表示。
可以使用dir函数来查看constants模块包含了哪些常量:
from scipy import constants print(dir(constants)) ['Avogadro','Boltzmann','Btu','Btu_IT','Btu_th','ConstantWarning','G','Julian_year','N_A', 'Planck','R','Rydberg','Stefan_Boltzmann','Wien',… 'yobi','yotta','zebi','zepto','zero_Celsius','zetta']
SciPy的optimize模块提供了常用的最优化算法函数实现,可以直接调用这些函数完成优化问题,如查找函数的最小值或方程的根等。
NumPy能够找到多项式和线性方程的根,但它无法找到非线性方程的根,如下所示:
x+cos(x)
因此可以使用SciPy的optimze.root函数,这个函数需要两个参数:
· fun:表示方程的函数。
· x0:根的初始猜测。
该函数返回一个对象,其中包含有关解决方案的信息。
在数学中,函数表示一条曲线,曲线有高点和低点。高点称为最大值,低点称为最小值。整条曲线中的最高点称为全局最大值,其余高点称为局部最大值。整条曲线的最低点称为全局最小值,其余的低点称为局部最小值。
可使用scipy.optimize.minimize函数来最小化函数。minimize函数接收以下几个参数:
· fun:要优化的函数。
· x0:初始猜测值。
· method:要使用的方法名称,值可以是'CG''BFGS''Newton-CG''L-BFGS-B''TNC''COBYLA'和'SLSQP'。
· callback:每次优化迭代后调用的函数。
· options:定义其他参数的字典。
【例1-16】 显示函数 x 2 + x +2的相关解决方案信息,并使用BFGS的最小化函数。
from scipy.optimize import root from scipy.optimize import minimize from math import cos def eqn(x): return x * * 2+x+2 myroot=root(eqn,0) #查看更多信息 print(myroot) fjac:array([[-1.]]) fun:array([1.75]) message:'The iteration is not making good progress,as measured by the\n improvement from the last ten iterations.' nfev:19 qtf:array([-1.75]) r:array([0.0019531]) status:5 success:False x:array([-0.49999999]) #最小化函数 mymin=minimize(eqn,0,method='BFGS') print(mymin) fun:1.75 hess_inv:array([[0.50000001]]) jac:array([0.]) message:'Optimization terminated successfully.' nfev:12 nit:2 njev:4 status:0 success:True x:array([-0.50000001])
稀疏矩阵(sparse matrix)指的是在数值分析中绝大多数数值为0的矩阵。反之,如果大部分元素都非0,则这个矩阵是稠密的(dense),如图1-30所示。
图1-30 稀疏矩阵与稠密矩阵
SciPy的scipy.sparse模块提供了处理稀疏矩阵相关的函数。在Python中主要使用以下两种类型的稀疏矩阵:
· CSC:压缩稀疏列(Compressed Sparse Column),按列压缩。
· CSR:压缩稀疏行(Compressed Sparse Row),按行压缩。
在SciPy中可以通过向scipy.sparse.csr_matrix函数传递数组来创建一个CSR矩阵,并可使用data属性查看存储的数据(不含0元素),下面通过实例来演示CSR矩阵的相关操作。
【例1-17】 创建CSR矩阵,并进行相关操作。
import numpy as np from scipy.sparse import csr_matrix #创建CSR矩阵 arr=np.array([0,0,0,0,0,1,1,0,2]) print(csr_matrix(arr))
运行程序,输出如下:
(0,5) 1 (0,6) 1 (0,8) 2
其中,
· 第1行:在矩阵第1行(索引值0)第6(索引值5)个位置有一个数值1。
· 第2行:在矩阵第1行(索引值0)第7(索引值6)个位置有一个数值1。
· 第3行:在矩阵第1行(索引值0)第9(索引值8)个位置有一个数值2。
#查看存储数据 print('查看存储数据:',csr_matrix(arr).data)
运行程序,输出如下:
查看存储数据:[1 1 2] #count_nonzero方法计算非0元素的总数 print('计算非0元素的总数:',csr_matrix(arr).count_nonzero())
运行程序,输出如下:
计算非0元素的总数:3 #使用eliminate_zeros方法删除矩阵中0元素 mat1=csr_matrix(arr) mat1.eliminate_zeros() print('删除矩阵中0元素:',mat1)
运行程序,输出如下:
删除矩阵中0元素:(0,5)1 (0,6) 1 (0,8) 2 #使用sum_duplicates方法来删除重复项 mat2=csr_matrix(arr) mat2.sum_duplicates() print('删除重复项:',mat2)
运行程序,输出如下:
删除重复项:(0,5) 1 (0,6) 1 (0,8) 2 #CSR矩阵转换为CSC矩阵使用tocsc方法 newarr=csr_matrix(arr).tocsc() print('转换为CSC矩阵:',newarr)
运行程序,输出如下:
转换为CSC矩阵:(0,5) 1 (0,6) 1 (0,8) 2
图结构是算法学中最强大的框架之一。图是各种关系的节点和边的集合,节点是与对象对应的顶点,边是对象之间的连接。SciPy提供了scipy.sparse.csgraph模块来处理图结构。
1)邻接矩阵
邻接矩阵(adjacency matrix)是表示顶点之间相邻关系的矩阵。邻接矩阵逻辑结构分为两部分,如图1-31所示。其中,V和E集合,V是顶点,E是边,边有时会有权重,表示节点之间的连接强度。
用一个一维数组存放图中所有顶点数据,用一个二维数组存放顶点间关系(边或弧)数据,这个二维数组称为邻接矩阵,如图1-32所示。
顶点有A、B、C,边权重有1和2,这个邻接矩阵可以表示为以下二维数组:
A B C A:[0 1 2] B:[1 0 0] C:[2 0 0]
图1-31 邻接矩阵
图1-32 二维数组的邻接矩阵
邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵。无向图是双向关系,边没有方向,如图1-33所示。
图1-33 无向图
有向图的边带有方向,是单向关系,如图1-34所示。
图1-34 有向图
提示: 图1-33和图1-34中的D节点是自环,自环是指一条边的两端为同一个节点。
2)Dijkstra算法
Dijkstra(迪杰斯特拉)算法是一种典型的最短路径算法,用于计算一个节点到其他所有节点的最短路径。SciPy使用dijkstra方法来计算一个元素到其他元素的最短路径。dijkstra方法可以设置以下几个参数:
· return_predecessors:布尔值,设置为True表示遍历所有路径,如果不想遍历所有路径可以设置为False。
· indices:元素的索引,返回该元素的所有路径。
· limit:路径的最大权重。
3)Floyd算法
Floyd(弗洛伊德)算法是解决任意两点间的最短路径的一种算法。SciPy使用floyd_warshall方法来查找所有元素对之间的最短路径。
4)Bellman Ford算法
Bellman Ford(贝尔曼-福特)算法是解决任意两点间的最短路径的一种算法。SciPy使用bellman_ford方法来查找所有元素对之间的最短路径,通常可以在任何图中使用,包括有向图、带负权边的图。
【例1-18】 几种算法的演示。
import numpy as np from scipy.sparse.csgraph import dijkstra from scipy.sparse import csr_matrix arr=np.array([ [0,1,2], [1,0,0], [2,0,0] ]) newarr=csr_matrix(arr) #查找元素1到2的最短路径 print(dijkstra(newarr,return_predecessors=True,indices=0)) (array([0.,1.,2.]),array([-9999, 0, 0])) from scipy.sparse.csgraph import floyd_warshall #查找所有元素对之间的最短路径 print(floyd_warshall(newarr,return_predecessors=True)) (array([[0.,1.,2.], [1.,0.,3.], [2.,3.,0.]]),array([[-9999, 0, 0], [ 1,-9999, 0], [ 2, 0,-9999]])) from scipy.sparse.csgraph import bellman_ford newarr=csr_matrix(arr) #使用负权边的图查找从元素 1到元素2的最短路径 print(bellman_ford(newarr,return_predecessors=True,indices=0)) (array([0.,1.,2.]),array([-9999,0,0]))
还可以从一个矩阵的深度和广度优先遍历节点。
【例1-19】 用不同方法遍历节点。
import numpy as np from scipy.sparse.csgraph import depth_first_order from scipy.sparse import csr_matrix arr=np.array([ [0,1,0,1], [1,1,1,1], [2,1,1,0], [0,1,0,1] ]) newarr=csr_matrix(arr) #depth_first_order方法从一个节点返回深度优先遍历的顺序 print(depth_first_order(newarr,1)) (array([1,0,3,2]),array([1,-9999,1,0])) #返回广度优先遍历的顺序 from scipy.sparse.csgraph import breadth_first_order print(breadth_first_order(newarr,1)) (array([1,0,2,3]),array([1,-9999,1,1]))
在数学的数值分析领域中,插值(interpolation)是一种通过已知的、离散的数据点,在范围内推求新数据点的过程或方法。简单来说,插值是一种在给定的点之间生成点的方法。SciPy提供了scipy.interpolate模块来处理插值。
1)一维插值
一维数据的插值运算可以通过方法interp1d完成。该方法接收两个参数x和y,返回值是可调用函数,该函数可以用新的x调用并返回相应的y,y=f(x)。
【例1-20】 对给定的xs和ys插值,从2.1、2.2到2.9。
from scipy.interpolate import interp1d import numpy as np xs=np.arange(10) ys=2 * xs+1 interp_func= interp1d(xs,ys) newarr= interp_func(np.arange(2.1,3,0.1)) print(newarr)
运行程序,输出如下:
[5.2 5.4 5.6 5.8 6. 6.2 6.4 6.6 6.8]
注意: 新的xs应该与旧的xs处于相同的范围内,这意味着不能使用大于10或小于0的值调用interp_func函数。
2)单变量插值
在一维插值中,点是针对单个曲线拟合的,而在样条插值中,点是针对使用多项式分段定义的函数拟合的。单变量插值使用UnivariateSpline函数,该函数接收xs和ys并生成一个可调用函数,该函数可以用新的xs调用。分段函数就是对于自变量x的不同的取值范围,有着不同的解析式的函数。
【例1-21】 为非线性点找到从2.1、2.2到2.9的单变量样条插值。
from scipy.interpolate import UnivariateSpline import numpy as np xs=np.arange(10) ys=xs * * 2+np.sin(xs)+1 interp_func=UnivariateSpline(xs,ys) newarr= interp_func(np.arange(2.1,3,0.1)) print(newarr)
运行程序,输出如下:
[5.62826474 6.03987348 6.47131994 6.92265019 7.3939103 7.88514634 8.39640439 8.92773053 9.47917082]
3)径向基函数插值
径向基函数是对应于固定参考点定义的函数。曲面插值中一般使用径向基函数插值。Rbf函数接收xs和ys作为参数,并生成一个可调用函数,该函数可以用新的xs调用。
Pandas是Python语言的一个扩展程序库,用于数据分析,它可以从各种文件格式如CSV、JSON、SQL、Microsoft Excel中导入数据。此外,Pandas可以对各种数据进行运算操作,如归并、再成形、选择、数据清洗和数据加工,它广泛应用在学术、金融、统计学等各个数据分析领域。
Pandas Series类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型。Series由索引(index)和列组成。其语法格式如下:
pandas.Series(data,index,dtype,name,copy)
其中,data为一组数据(ndarray类型);index为数据索引标签,如果不指定,默认从0开始;dtype为数据类型,默认会自己判断;name用于设置名称;copy用于复制数据,默认为False。
【例1-22】 创建一个简单的Series实例。
import pandas as pd a=[1,2,3] myvar=pd.Series(a) print(myvar)
运行程序,效果如图1-35所示。
图1-35 简单的Series实例
从图1-35可知,如果没有指定索引,索引值就从0开始。也可以使用key/value对象,类似字典来创建Series。
【例1-23】 利用key/value对象创建Series。
import pandas as pd sites={1:"Google",2:"Python",3:"Wiki"} var=pd.Series(sites) print(var)
运行程序,输出如下:
1 Google 2 Python 3 Wiki dtype:object
从以上结果可知,字典的key变成了索引值。如果只需要字典中的一部分数据,则只指定需要数据的索引即可。
还可设置Series名称参数:
var=pd.Series(sites,index=[1,2],name="RUNOOB-Series-TEST") print(var) 1 Google 2 Python Name:RUNOOB-Series-TEST,dtype:object
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame既有行索引又有列索引,它可以被看作由Series组成的字典(共同用一个索引)。其构造方法如下:
pandas.DataFrame(data,index,columns,dtype,copy)
其中,data为一组数据(ndarray、series、map、lists、dict等类型);index为索引值,或者可以称为行标签;columns为列标签,默认为RangeIndex(0,1,2,…,n);dtype为数据类型;copy用于复制数据,默认为False。
Pandas DataFrame是一个二维的数组结构,类似二维数组。
【例1-24】 使用ndarray创建列表。
解析:ndarray的长度必须相同,如果传递了index(索引),则索引的长度应等于数组的长度。如果没有传递索引,则默认情况下,索引将是range(n),其中n是数组长度。
import pandas as pd data={'Site':['Google','Python','Wiki'],'Age':[9,10,11]} df=pd.DataFrame(data) print(df)
运行程序,输出如下:
Site Age 0 Google 9 1 Python 10 2 Wiki 11
从以上输出结果可以知道,DataFrame数据类型是一个表格,包含row(行)和column(列),如图1-36所示。
图1-36 DataFrame数据类型
Pandas可以使用loc属性返回指定行的数据,如果没有设置索引,第一行索引为0,第二行索引为1,以此类推。
import pandas as pd data={ "calories":[360,390,400], "duration":[50,40,45] } #数据载入DataFrame对象 df=pd.DataFrame(data) #返回第一行 print(df.loc[0]) calories 360 duration 50 Name:0,dtype:int64 #返回第二行 print(df.loc[1]) calories 390 duration 40 Name:1,dtype:int64
注意: 返回结果其实就是一个Pandas Series数据。
也可以返回多行数据,使用[[…]]格式,…为各行的索引,以逗号隔开:
#数据载入DataFrame对象 df=pd.DataFrame(data) #返回第一行和第二行 print(df.loc[[0,1]]) calories duration 0 360 50 1 390 40
注意: 返回结果其实就是一个Pandas DataFrame数据。
Pandas可以使用loc属性返回指定索引对应到某一行:
df=pd.DataFrame(data,index=["day1","day2","day3"]) #指定索引 print(df.loc["day2"]) calories 390 duration 40 Name:day2,dtype:int64
CSV(Comma-Separated Value,逗号分隔值,有时也称为字符分隔值,因为分隔字符也可以不是逗号)文件以纯文本形式存储表格数据(数字和文本)。CSV是一种通用的、相对简单的文件格式,被用户、商业和科学广泛应用。
【例1-25】 打开nba.csv文件。
import pandas as pd df=pd.read_csv('nba.csv') print(df.to_string())
to_string用于返回DataFrame类型的数据,如果不使用该函数,则输出结果为数据的前面5行和末尾5行,中间部分以…代替,接上面代码:
print(df) Name Team Number Position Age \ 0 Avery Bradley Boston Celtics 0.0 PG 25.0 1 Jae Crowder Boston Celtics 99.0 SF 25.0 2 John Holland Boston Celtics 30.0 SG 27.0 … 456 7-0 231.0 Kansas 947276.0 457 NaN NaN NaN NaN [458 rows x 9 columns]
也可以使用to_csv方法将DataFrame存储为CSV文件:
import pandas as pd #三个字段name,site,age nme=["Google","Python","baidu","Taobao"] st=["www.google.com","https://www.sciclass.cn/python","https://www.baidu.com/","www. taobao.com"] ag=[85,41,83,96] #字典 dict={'name':nme,'site':st,'age':ag} df=pd.DataFrame(dict) #保存DataFrame
运行程序,打开site.csv文件,显示结果如图1-37所示。
图1-37 site.csv文件
JSON(JavaScript Object Notation,JavaScript对象表示法)是存储和交换文本信息的语法,类似于XML。JSON比XML更小、更快、更易解析。
sites.json的代码如下:
[ { "id":"A001", "name":"baidu", "url":"www.baidu.com", "likes":6159 }, { "id":"A002", "name":"Google", "url":"www.google.com", "likes":124 }, { "id":"A003", "name":"taobao", "url":"www.taobao.com", "likes":45 } ]
【例1-26】 读取sites.json文件。
import pandas as pd df=pd.read_json('sites.json') print(df.to_string()) to_string() #用于返回DataFrame类型的数据,也可以直接处理JSON字符串 import pandas as pd data=[ { "id":"A001", "name":"baidu", "url":"www.baidu.com", "likes":6159 }, { "id":"A002", "name":"Google", "url":"www.google.com", "likes":124 }, { "id":"A003", "name":"taobao", "url":"www.taobao.com", "likes":45 } ] df=pd.DataFrame(data) print(df)
运行程序,输出如下:
id likes name url 0 A001 6159 baidu www.baidu.com 1 A002 124 Google www.google.com 2 A003 45 taobao www.taobao.com
JSON对象与Python字典具有相同的格式,所以可以直接将Python字典转换为DataFrame数据。
假设有一组内嵌的JSON数据文件nested_list.json,nested_list.json文件内容如下:
{ "school_name":"ABC primary school", "class":"Year 1", "students":[ { "id":"A001", "name":"Tom", "math":60, "physics":66, "chemistry":61 }, { "id":"A002", "name":"James", "math":89, "physics":76, "chemistry":51 }, { "id":"A003", "name":"Jenny", "math":79, "physics":90, "chemistry":78 }] }
可使用以下代码格式化完整内容:
import pandas as pd df=pd.read_json('nested_list.json') print(df) school_name class students 0 ABC primary school Year 1 {'id':'A001','name':'Tom','math':60,'phy... 1 ABC primary school Year 1 {'id':'A002','name':'James','math':89,'p... 2 ABC primary school Year 1 {'id':'A003','name':'Jenny','math':79,'p...