美文网首页
《Python数据分析第二章》

《Python数据分析第二章》

作者: 带刺的小花_ea97 | 来源:发表于2018-12-23 04:10 被阅读18次

    本章涉及的主题如下:

    • 数据类型
    • 数组类型
    • 类型转换
    • 创建数组
    • 索引
    • 花式索引
    • 切片
    • 处理数组的形状
    2.1NumPy数组对象

    NumPy中的多为数组成为ndarray,它有两个组成部分。

    • 数据本身
    • 描述数据的元数据
      在数组的处理过程中,原始信息不受影响,变化的只是元数据而已。
      在第一章中,我们曾经用arange()函数来生成数组。实际上,那是用来存放一组数值的一维数组,这里的nadarray则可以具有一个以上的维度。

    NumPy数组的优势
    NumPy数组通常是由相同种类的元素组成的,即数组中的数据项的类型必须一致。NumPy数组元素类型一致的好处是:由于知道数组元素的类型相同,所以能轻松确定存储数组所需空间的大小。同时,NumPy数组还能够运用向量化运算来处理整个数组;而完成同样的任务,Python的列表则通常必须借助循环语句便利列表,并对逐个元素进行相应的处理。此外,NumPy使用了优化过的CAPI,所以运算速度格外快。

    NumPy数组的索引方法和Python类似,下标从0开始。

    我们来创建一个数组试一下,查看它的数据类型和形状

    import numpy as np
    a = np.arange(5)
    print(a.dtype)
    print(a)
    print(a.shape)
    

    输出结果为:

    int32
    [0 1 2 3 4]
    (5,)
    

    因为我的Python是32位版本,所以得到的结果是int32;如你所见,该向量有5个元素,它们的值分别是0到4。该数组的shape属性是一个元组,这是一个单元素数组,所以存放的是每一个数组在每一个维度的长度。

    2.2创建多维数组
    import numpy as np
    from numpy import  array
    m = array([np.arange(2), np.arange(2)])
    print(m)
    print(m.shape)
    

    运行结果:

    [[0 1]
     [0 1]]
    (2, 2)
    

    注意这里需要从numpy中Import array包。
    在这里,我们直接用np.arrange()创建了2 X 2的数组,利用array()函数创建数组时,需要传递给它一个对象,而且这个对象必须是数组类型的,如Python列表。

    2.3选择NumPy数组元素
    import numpy as np
    from numpy import  array
    a = array([[1,2], [3,4]])
    print(a)
    print(a[0, 0])
    print(a[0, 1])
    print(a[1, 0])
    print(a[1, 1])
    

    运行结果:

    [[1 2]
     [3 4]]
    1
    2
    3
    4
    

    上面的矩阵是通过向array()函数传递一个由列表组成的列表得到的,然后通过逐个选择矩阵的各个元素,记住下标是从0开始的。
    选择数组是一件非常简单的事,对于数组a,只要通过a[m, n]的形式,就能访问数组内的元素,其中m和n分别为数组元素的下标。

    2.4NumPy的数值类型

    Python自身虽然支持整型、浮点型和复数型,但是对于科学计算来说,还远远不够,我们需要更多的数据类型,来满足精度和存储大小方面的各种不同要求。为此,NumPy提供了更加丰富的数据类型。而每一种数据类型都具有相应的转换函数:

    print(float(42))
    print(int(42.0))
    print(bool(42))
    print(bool(0))
    print(float(True))
    print(float(False))
    

    运行结果:

    42.0
    42
    True
    False
    1.0
    0.0
    

    许多函数都带有一个制定数据类型的参数,这个参数通常是可选的:

    import numpy as np
    from numpy import array
    np.arange(7, dtype = np.uint16)
    

    输出结果:

    array([0, 1, 2, 3, 4, 5, 6], dtype=uint16)
    

    注意,这里的dtype类型中的数据类型也要指定伟np.uint。
    谨记:不允许把复数类型转化为整型。同样,也不允许把复数转化为浮点数,此外,复数的分量j是其虚部的系数,允许把浮点数转化为复数,如complex(1, 0)是合法的,复数的实部和虚部分别使用real()函数和imag()函数提取。

    2.4.1数据类型对象

    数据类型对象是numpy.dtype类的实例。数组是一种数据类型。严格来讲,NumPy数组中的每个元素都要具有相同的数据类型。数据类型表明了数据占用的字节数,所以占用字节的具体数目一般存放在类dtype的itemsize属性中。

    a.dtype.itemsize
    

    输出结果:

    4
    
    2.4.2字符码

    啥是字符码,我的理解就是用一个代码表示数据类型,这样可以简化程序,比如:

    import numpy as np
    from numpy import array
    a = np.arange(7, dtype = 'f')
    b = np.arange(7, dtype = "D")
    print(a, b)
    

    输出结果:

    [0. 1. 2. 3. 4. 5. 6.] [0.+0.j 1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j 6.+0.j]
    
    2.4.3Dtype构造函数

    创建数据类型时,手段有很多。

    • 可以使用Python自带的常规浮点数型
    • 可以使用字符码规定单精度浮点数
    • 可以用字符码定义双精度浮点数
    • 可以向dtype构造函数传递一个双字符码。其中,第一个字符表示数据类型,第二个字符是一个数字,表示该类型占用的字节数。
    import numpy as np
    from numpy import array
    print(np.dtype(np.float))
    print(np.dtype('f'))
    print(np.dtype('d'))
    print(np.dtype('f8'))
    

    输出结果:

    float64
    float32
    float64
    float64
    
    2.4.4dtype属性
    import numpy as np
    t = np.dtype('Float64')
    print(t.char)
    print(t.type)
    print(t.str)
    

    输出结果:

    d
    <class 'numpy.float64'>
    <f8
    

    其第一行返回其字符码;第二行返回其类型属性;第三行中dtype的属性str中保存的是一个表示数据类型的字符串,其中第一个字符描述的是数据类型,如果需要,后面会跟着字符码和数组,用来存储每个数组元素所需的字节数。

    2.5一维数组的切片和索引

    一维NumPy数组的切片操作与Python列表的切片一样。

    import numpy as np
    from numpy import array
    a = np.arange(9)
    print(a[3 : 7])    #指定下标选择数组的部分元素
    print(a[:7 :2])    #制定下标选择元素,并设定下标每次递增2  
    print(a[::-1])    #用负值下标翻转数组
    

    输出结果:

    [3 4 5 6]
    [0 2 4 6]
    [8 7 6 5 4 3 2 1 0]
    
    2.6处理数组形状

    前面,我们学习过reshape()函数,实际上,除了数组形状的调整外,数组的扩充也是一个经常碰到的乏味工作。

    import numpy as np
    b = np.arange(24).reshape(2, 3, 4)
    print(b,"\n")
    c = b.ravel()
    print(c,"\n")
    d = b.flatten()
    print(d,"\n")
    b.shape = (6, 4)
    print(b,"\n")
    e = b.transpose()
    print(e,"\n")
    b.resize((2, 12))
    print(b,"\n")
    

    输出结果:

    [[[ 0  1  2  3]
      [ 4  5  6  7]
      [ 8  9 10 11]]
    
     [[12 13 14 15]
      [16 17 18 19]
      [20 21 22 23]]] 
    
    [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23] 
    
    [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23] 
    
    [[ 0  1  2  3]
     [ 4  5  6  7]
     [ 8  9 10 11]
     [12 13 14 15]
     [16 17 18 19]
     [20 21 22 23]] 
    
    [[ 0  4  8 12 16 20]
     [ 1  5  9 13 17 21]
     [ 2  6 10 14 18 22]
     [ 3  7 11 15 19 23]] 
    
    [[ 0  1  2  3  4  5  6  7  8  9 10 11]
     [12 13 14 15 16 17 18 19 20 21 22 23]] 
    

    这里有一个细节问题:

    • reshape:有返回值,所谓有返回值,即不对原始多维数组进行修改;
    • resize:无返回值,所谓有返回值,即会对原始多维数组进行修改;

    即这里resize()函数会直接修改原数组,而不是输出新的数值!

    代码中的函数都是处理对数组的形状进行处理:

    • 拆解:ravel()函数将多维数组变成一维数组。
    • 拉直:Flatten()函数功能与ravel()相同,但是flatten()返回的是真实的数组,需要分配新的内存空间;而ravel()函数返回的只是数组的视图。
    • 用元组指定数组形状:除了reshape()函数外,还可以用元组来轻松定义数组的形状
    • 转置:在线性代数中,矩阵的转置操作非常常见。转置是一种数据变换方法,对于二维表而言,转置就意味着行变成列,列变成行。
    • 调整大小,作用类似于reshape(),但是会改变所作用的数组。
    2.6.1堆叠数组

    从深度看,数组既可以横向叠放,也可以竖向叠放。为此,可以使用vstack()、dstack()、hstack()、column_stack()、row_stack()和concatenate()等函数。

    import numpy as np
    a = np.arange(9).reshape(3, 3)
    print(a,"\n")
    b = 2 * a 
    print(b,"\n")
    c = np.hstack((a, b))    #水平叠加
    print(c,"\n")
    d = np.concatenate((a, b), axis = 1)    #用concatenate()函数参数axis = 1实现水平叠加效果
    print(d,"\n")
    e = np.vstack((a, b))    #垂直叠加
    print(e,"\n")
    f = np.concatenate((a, b), axis = 0)    #用concatenate()函数参数axis = 0实现垂直叠加效果
    print(f,"\n")
    g = np.dstack((a, b))    #深度叠加
    print(g, "\n")
    
    oned = np.arange(2)   
    print(oned, "\n")
    twice_oned = 2 * oned
    print(twice_oned, "\n")
    h = np.column_stack((oned, twice_oned))     #列式叠加
    print(h, "\n")
    i = np.column_stack((a, b))    #这种列式叠加有点类似于hstack水平叠加
    print(i, "\n")
    
    print(i == c,"\n")
    
    j = np.row_stack((oned, twice_oned))    #行式叠加
    print(j,"\n")
    k = np.row_stack((a, b))    #这种列式叠加有点类似于vstack垂直叠加
    print(k,"\n")
    
    print(e == k,"\n")
    

    输出结果:

    [[0 1 2]
     [3 4 5]
     [6 7 8]] 
    
    [[ 0  2  4]
     [ 6  8 10]
     [12 14 16]] 
    
    [[ 0  1  2  0  2  4]
     [ 3  4  5  6  8 10]
     [ 6  7  8 12 14 16]] 
    
    [[ 0  1  2  0  2  4]
     [ 3  4  5  6  8 10]
     [ 6  7  8 12 14 16]] 
    
    [[ 0  1  2]
     [ 3  4  5]
     [ 6  7  8]
     [ 0  2  4]
     [ 6  8 10]
     [12 14 16]] 
    
    [[ 0  1  2]
     [ 3  4  5]
     [ 6  7  8]
     [ 0  2  4]
     [ 6  8 10]
     [12 14 16]] 
    
    [[[ 0  0]
      [ 1  2]
      [ 2  4]]
    
     [[ 3  6]
      [ 4  8]
      [ 5 10]]
    
     [[ 6 12]
      [ 7 14]
      [ 8 16]]] 
    
    [0 1] 
    
    [0 2] 
    
    [[0 0]
     [1 2]] 
    
    [[ 0  1  2  0  2  4]
     [ 3  4  5  6  8 10]
     [ 6  7  8 12 14 16]] 
    
    [[ True  True  True  True  True  True]
     [ True  True  True  True  True  True]
     [ True  True  True  True  True  True]] 
    
    [[0 1]
     [0 2]] 
    
    [[ 0  1  2]
     [ 3  4  5]
     [ 6  7  8]
     [ 0  2  4]
     [ 6  8 10]
     [12 14 16]] 
    
    [[ True  True  True]
     [ True  True  True]
     [ True  True  True]
     [ True  True  True]
     [ True  True  True]
     [ True  True  True]] 
    

    这里有一个细节问题:
    堆叠函数的参数是一个元组的时候,要转换两个数组为一个元组,即用两个括号将两个数组括起来组成一个元组。

    堆放数组的方法总结如下:

    • 水平叠加
    • 垂直叠加
    • 深度叠加:这种方法是沿着第三个坐标轴(纵向)的方向叠加一摞数组,可以在一个图像数据的二维数组上叠加另一幅图像的数据。
    • 列式堆叠
    • 行式堆叠
    2.6.2拆分NumPy数组

    可以从纵向、横向和深度方向来拆分数组,相关函数有hsolit()、vsplit()、dsplit()和split()。我们既可以把数组分成相同形状的数组,也可以从规定的位置开始切取数组。

    import numpy as np
    a = np.arange(9).reshape(3, 3)
    print(a,"\n")
    b = np.hsplit(a, 3)    #横向拆分
    print(b,"\n")    
    c = np.split(a, 3, axis = 1)    #相当于调用参数axis = 1的split()函数
    print(c,"\n")
    d = np.vsplit(a, 3)     #纵向拆分
    print(d,"\n")
    e = np.split(a, 3, axis = 0)     #相当于调用参数axis = 0的split()函数
    print(e,"\n")
    f = np.arange(27).reshape(3, 3, 3)    
    print(f,"\n")
    g = np.dsplit(f, 3)    #沿着深度方向分解数组,本例秩为3
    print(g,"\n")
    

    输出结果:

    [[0 1 2]
     [3 4 5]
     [6 7 8]] 
    
    [array([[0],
           [3],
           [6]]), array([[1],
           [4],
           [7]]), array([[2],
           [5],
           [8]])] 
    
    [array([[0],
           [3],
           [6]]), array([[1],
           [4],
           [7]]), array([[2],
           [5],
           [8]])] 
    
    [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])] 
    
    [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])] 
    
    [[[ 0  1  2]
      [ 3  4  5]
      [ 6  7  8]]
    
     [[ 9 10 11]
      [12 13 14]
      [15 16 17]]
    
     [[18 19 20]
      [21 22 23]
      [24 25 26]]] 
    
    [array([[[ 0],
            [ 3],
            [ 6]],
    
           [[ 9],
            [12],
            [15]],
    
           [[18],
            [21],
            [24]]]), array([[[ 1],
            [ 4],
            [ 7]],
    
           [[10],
            [13],
            [16]],
    
           [[19],
            [22],
            [25]]]), array([[[ 2],
            [ 5],
            [ 8]],
    
           [[11],
            [14],
            [17]],
    
           [[20],
            [23],
            [26]]])] 
    
    2.6.3NumPy数组的属性

    除shape和dtype属性外,ndarray类型的属性还很多:

    • ndim属性存储的是维度的数量
    • size属性用来保存元素的数量
    • itemsize属性可以返回数组中各个元素所占用的字节数
    • 如果想知道存储整个数组所需的字节数量,可以求助于nbytes属性,这个属性值正好是itemsize属性值和size属性值之积。
      -T属性的作用与transpose()函数相同
    • 如果数组的秩(rank)小于2,那么所得只是一个数组的视图:这里其实有个小问题,我认为这个矩阵的秩为1,但是输出确是2,所以这里也体现不了得到视图的效果(因为秩为1嘛)。比如:
    a = np.array([[1, 2, 3, 4],
        [2, 4, 6, 8]])
    print(a.ndim)
    

    输出结果为2,这里我觉得这很明显是秩为1的矩阵啊!

    • 对于NumPy来说,复数用j表示
    • real属性将返回数组的实部,当数组元素全为实数时,就返回数组本身
    • imag属性存放的是数组的虚部
    • 如果数组含有复数,那么它的数据类型将自动变为复数类型
    • flat属性可返回一个numpy.flatiter对象,这是获得flatiter对象的唯一方法,但我们无法访问flatiter的构造函数。可以通过flat[1, 3]获取对象中的元素,此外还可以给flat属性赋值,不过需要注意的是,这个值将会覆盖整个数组内的所有元素的值。
    import numpy as np
    from numpy import array
    a = np.arange(24).reshape(2, 12)
    print(a,"\n")
    print(a.ndim,"\n")    #求其维度的数量
    print(a.size,"\n")    #求其保存元素的数量
    print(a.itemsize,"\n")    #返回数组中各个元素所占用的字节数
    print(a.nbytes,"\n")    #整个数组所需的字节数量
    print(a.size * a.itemsize,"\n")
    a.resize(6, 4)
    print(a,"\n")
    print(a.T,"\n")    #转置
    print(a.ndim,"\n")    #这里矩阵的秩为什么是2!!!!!!!!!!
    a = np.array([1.j + 1, 2.j + 3])
    print(a,"\n")
    print(a.real,"\n")    #返回数组的实部
    print(a.imag,"\n")    #返回数组的虚部
    print(a.dtype,"\n")    #返回复数的数据类型
    print(a.dtype.str,"\n")
    a = np.arange(4).reshape(2,2)
    print(a,"\n")
    b = a.flat    #flat函数就像迭代器一样读取每个数组
    print(b,"\n")
    for it in b:
        print(it,"\n")
    print(a.flat[2],"\n")
    print(a.flat[[1, 3]],"\n")
    print(a,"\n")
    a.flat[[1, 3]] = 7
    print(a,"\n")
    a.flat = 7
    print(a,'\n')
    

    输出结果:

    [[ 0  1  2  3  4  5  6  7  8  9 10 11]
     [12 13 14 15 16 17 18 19 20 21 22 23]] 
    
    2 
    
    24 
    
    4 
    
    96 
    
    96 
    
    [[ 0  1  2  3]
     [ 4  5  6  7]
     [ 8  9 10 11]
     [12 13 14 15]
     [16 17 18 19]
     [20 21 22 23]] 
    
    [[ 0  4  8 12 16 20]
     [ 1  5  9 13 17 21]
     [ 2  6 10 14 18 22]
     [ 3  7 11 15 19 23]] 
    
    2 
    
    [1.+1.j 3.+2.j] 
    
    [1. 3.] 
    
    [1. 2.] 
    
    complex128 
    
    <c16 
    
    [[0 1]
     [2 3]] 
    
    <numpy.flatiter object at 0x04AEAB70> 
    
    0 
    
    1 
    
    2 
    
    3 
    
    2 
    
    [1 3] 
    
    [[0 1]
     [2 3]] 
    
    [[0 7]
     [2 7]] 
    
    [[7 7]
     [7 7]] 
    
    2.6.4数组的转换

    可以把NumPy数组转换成Python列表,使用tolist()函数。

    • 转换成列表
    • astype()函数可以把数组元素转换成制定类型
      提示:当complex类型转换成int类型时,虚部将被丢弃,此外,还需要将数据类型的名称以字符串的形式传递给astype()函数。
    import numpy as np
    from numpy import array
    a = np.array([1 + 1.j, 3 + 2.j])
    b = a.astype(int)
    print(b)
    c = a.tolist()
    print(c)
    d = b.astype('complex')
    print(d)
    

    输出结果:

    [1 3]
    [(1+1j), (3+2j)]
    [1.+0.j 3.+0.j]
    D:\Python\lib\site-packages\ipykernel_launcher.py:4: ComplexWarning: Casting complex values to real discards the imaginary part
      after removing the cwd from sys.path.
    
    2.7创建数组的视图和拷贝

    在NumPy的师姐中,视图不是只读的,因为你不可能守着基础数据一动不动,关键在于要知道,当前处理的是共享的数组视图,还是数组数据的副本。举例来说,可以使用数组的一部分生成视图。这意味着,如果先将数组的某部分赋予给一个变量,然后修改原数组中相应位置的数据,那么这个变量的值也会随之变化。我们可以根据著名的莱娜照片创建数组,然后创建视图,随后修改它。
    因为莱娜图片已经被scipy移除,这里用替换文件ascent代替:

    import scipy.misc    #从scipy中获取图像数组
    import matplotlib.pyplot as plt    #获取画图matplotlib库用于绘图和显示
    
    ascent = scipy.misc.ascent()    #获取
    acopy = ascent.copy()
    aview = ascent.view()
    plt.subplot(221)
    plt.imshow(ascent)
    plt.subplot(222)
    plt.imshow(acopy)
    plt.subplot(223)
    plt.imshow(aview)
    aview.flat = 0
    plt.subplot(224)
    plt.imshow(aview)
    plt.show()
    

    输出结果:

    哈哈这里反而产生了一个相悖的结论,这里在程序结束部分修改视图,同时改变了原来的图片数组,导致134图都应该变紫,表明除了复制的数组,其他数组都被程序结尾的改变而改变,证明:视图不是只读的。但是这里原图和视图都没变!!!

    2.8花式索引

    花式索引是一种传统的索引方法,它不使用整数或切片。这里我们利用花式索引将楼梯照片对角线上的值全部置0,相当于沿着两条交叉的对象线画两条黑线。

    import scipy.misc   
    import matplotlib.pyplot as plt    
    
    ascent = scipy.misc.ascent()  
    xmax = ascent.shape[0]    
    ymax = ascent.shape[1]    
    ascent[range(xmax), range(ymax)] = 0    #给x和y值规定两个不同的范围
    ascent[range(xmax-1, -1, -1), range(ymax)] = 0    #规定两个不同的取值范围,但是规则不变
    plt.imshow(ascent)
    plt.show()
    

    输出结果:

    我们给x和y规定了两个不同的取值范围,这些范围来索引图片。花式索引是在一个内部的NumPy迭代器对象的基础上实现的,分3步完成。
    (1)创建迭代器对象
    (2)将迭代器对象绑定到数组
    (3)经由迭代器访问数组元素,利用位置列表进行索引。

    我的解释:把图片转换为数组后,定义max(512:黑色),然后利用range()函数将对角线设置为黑色。

    2.9基于位置列表的索引方法
    import scipy.misc   
    import matplotlib.pyplot as plt   
    import numpy as np
    
    ascent = scipy.misc.ascent()  
    xmax = ascent.shape[0]    
    ymax = ascent.shape[1] 
    
    def shuffle_indices(size):
        arr = np.arange(size)
        np.random.shuffle(arr)    #shuffle()函数将数组中的元素按随机的索引号重新排列
        
        return arr
    
    xindices = shuffle_indices(xmax)
    np.testing.assert_equal(len(xindices), xmax)
    yindices = shuffle_indices(ymax)
    np.testing.assert_equal(len(yindices), ymax)
    plt.imshow(ascent[np.ix_(xindices, yindices)])    #画出打乱后的索引
    plt.show()
    

    运行结果:

    这里解释两个函数:

    • shuffle函数:
    import random
    
    list = [20, 16, 10, 5];
    random.shuffle(list)
    print(list)
    random.shuffle(list)
    print(list)
    

    运行结果:

    [20, 16, 5, 10]
    [10, 5, 16, 20]
    
    • ix_()函数
      这个函数可以根据多个序列生成一个网格,他需要一个一维序列作为参数,并返回一个由NumPy数组构成的元组。
    import numpy as np
    np.ix_([0, 1], [2, 3])
    

    运行结果:

    (array([[0],
            [1]]), array([[2, 3]]))
    
    2.10用布尔型变量索引NumPy数组

    布尔型索引是根据布尔型数组来索引元素的方法,属于花式索引系列。

    import scipy.misc   
    import matplotlib.pyplot as plt   
    import numpy as np
    
    ascent = scipy.misc.ascent() 
    
    def get_indices(size):
        arr = np.arange(size)
        return arr % 4 == 0
    
    ascent = ascent.copy()
    xindices = get_indices(ascent.shape[0])
    yindices = get_indices(ascent.shape[1])
    ascent[xindices, yindices] = 0
    plt.subplot(211)
    plt.imshow(ascent)
    ascent2 = ascent.copy()
    ascent2[((ascent > ascent.max()/4) & (ascent < 3 * ascent.max()/4))] = 0
    plt.subplot(212)
    plt.imshow(ascent2)
    plt.show()
    

    运行结果:

    1.定义函数,在对角线上画点,选择的是照片对角线上可以被4整除的那些位置上的点,然后仅绘出选定的那些点。
    2.根据元素值的情况置0。选择数组值结余最大值的1/4到3/4的那些元素将其置0.

    这里有个小问题就是书中源代码是会报错的,报错信息如下:

    TypeError: ufunc 'bitwise_and' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
    

    这是因为第18行的运算优先级问题,在上述两种情况下都加上()就没问题了。

    2.11NumPy数组的广播

    当操作对象的形状不一样时,NumPy会尽力进行处理。
    例如,假设一个数组要跟一个标量想乘,这时标量需要根据数组的形状进行扩展,然后才可以执行乘法运算,这个扩展过程叫做广播

    import scipy.io.wavfile
    import matplotlib.pyplot as plot
    import urllib.request
    import numpy as np
    response = urllib.request.urlopen('http://www.thesoundarchive.com/austinpowers/smashingbaby.wav')
    print(response.info)
    WAV_FILE = 'smashingbaby.wav'
    filehandle = open(WAV_FILE, 'wb+')
    filehandle.write(response.read())
    filehandle.close()
    sample_rate, data = scipy.io.wavfile.read(WAV_FILE)
    print("Data type", data.dtype, "Shape", data.shape)
    plt.subplot(2, 1, 1)
    plt.title("Original")
    plt.plot(data)
    newdata = data * 0.2
    newdata = newdata.astype(np.uint8)
    print("Data type", newdata.dtype, "shape", newdata.shape)
    scipy.io.wavfile.write("quiet.wav",
                          sample_rate, newdata)
    plt.subplot(2, 1, 2)
    plt.title("Quiet")
    plt.plot(newdata)
    plt.show()
    

    输出结果:

    <bound method HTTPResponse.info of <http.client.HTTPResponse object at 0x0E290D10>>
    Data type uint8 Shape (43584,)
    Data type uint8 shape (43584,)
    

    这个程序下载一个音频文件,然后以此为基础,生成一个新的静音版本。
    1.读取WAV文件
    哈哈这里幸亏已经看了爬虫,也说明了数据获取的重要性,虽然这一章应该focus在数据处理上,书中的代码应该修改urrlib2伟urrlib2.request,这是python3区别之前的地方之一,此外,书中的代码对于写入音频文件如果用w模式会报错:

    TypeError: write() argument must be str, not bytes
    

    这是因为:

    可能又是版本变化问题吧!这里通过爬虫的形式从电影《王牌大间谍》中下载狂嚎式的歌曲,Scipy中有一个wavfile子程序包,用来加载音频数据,或者生成WAV格式的文件。可以使用read()函数直接读取文件,它返回一个数据阵列及采样率。
    2.回执WAV原始数据
    3.新建一个数组
    现在,用NumPy生成一段寂静的声音,实际上就是将原数组乘以一个常数,从而得到一个新数组,因为这个新数组的元素值肯定是变小了,这就是广播术的用武之地。最后,我们要确保新数组和原数组的类型一致。即WAV格式。
    4.写入一个WAV文件中
    5.绘制出新的WAV数据
    6.展示原始的WAV文件中的数值图像,以及数值变小后的新数组的图像。

    可以听一下效果!哈哈真的消音了。

    2.12小结

    本章,学习了NumPy的基础知识:数据类型和数组。数组有很多属性,这些属性都是用来描述该数组的特性的。
    与Python标准的列表相比,NumPy数组使用的切片和索引方法更加高效,此外,NumPy数组还能够对多维数组进行处理。
    我们可以用各种方式改变数组的形状,如堆叠、重定尺寸、重塑形状以及拆分等。
    有了这些基础知识后,从第三章开始,就要学习如何通过常见的函数来分析数据了,这将涉及主要统计函数和数值函数的用法。

    咳咳

    数组学了很多遍,但是这次应该是比较系统的整理了一遍,Python这个语法就是很多,知道怎么用但是真的实际用就笨手笨脚,还是不能熟能生巧!
    这一章中对图片和音频的数据处理实例说明数据处理不是简简单单的处理数据,数据类型非常多,通过数据转换,可以将现实世界中的很多问题转换为数学运算的方式解决。
    线性代数补考才过,现在重新需要用到了,还有点慌,哈哈,秩都不会算了!
    记录可以让我不囫囵吞枣式的看书,边看边记录可能也会记的更深一点吧哈哈!真的喜欢简书的这种书写方式,

    相关文章

      网友评论

          本文标题:《Python数据分析第二章》

          本文链接:https://www.haomeiwen.com/subject/fwgikqtx.html