购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.8 用于机器学习的软件包

Python有许多吸引力,如效率、代码可读性和速度,使其成为数据科学爱好者的首选编程语言。它拥有大量的库,使数据科学家可以更轻松地完成复杂的任务,而无须编写很多代码。本节将对数据科学的前三个Python库进行介绍。

1.8.1 NumPy软件包

NumPy(Numerical Python)是Python语言的一个扩展程序库,支持大量的维度数组与矩阵运算,它是一个运行速度非常快的数学库,主要用于数组计算。

1.NumPy的ndarray对象

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]]
2.NumPy数据类型

数据类型对象(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')]
3.NumPy数组属性

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]
4.使用NumPy创建数组

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.]
5.数组操作

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]])]
6.NumPy算术函数

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.]]

1.8.2 SciPy软件包

SciPy是一个开源的Python算法库和数学工具包。它是基于NumPy的科学计算库,用于数学、科学、工程学等领域,很多高阶抽象和物理模型都需要使用SciPy。

1.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']
2.SciPy优化器

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])
3.SciPy稀疏矩阵

稀疏矩阵(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
4.SciPy图结构

图结构是算法学中最强大的框架之一。图是各种关系的节点和边的集合,节点是与对象对应的顶点,边是对象之间的连接。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]))
5.SciPy插值

在数学的数值分析领域中,插值(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调用。

1.8.3 Pandas软件包

Pandas是Python语言的一个扩展程序库,用于数据分析,它可以从各种文件格式如CSV、JSON、SQL、Microsoft Excel中导入数据。此外,Pandas可以对各种数据进行运算操作,如归并、再成形、选择、数据清洗和数据加工,它广泛应用在学术、金融、统计学等各个数据分析领域。

1.Pandas Series

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
2.Pandas DataFrame

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
3.Pandas CSV文件

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文件

4.Pandas JSON

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
       }]
    }

可使用以下代码格式化完整内容: tjUffkSjxyd+E6BqxZ/gaJYKkxa8OO6iRYd9Sf5LoKACVnJfxVLR/hsh+Yc1Exgt

    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...
点击中间区域
呼出菜单
上一章
目录
下一章
×