Skip to content

Latest commit

 

History

History
796 lines (545 loc) · 16.4 KB

67.NumPy的应用.md

File metadata and controls

796 lines (545 loc) · 16.4 KB

NumPy的应用

Numpy是一个开源的Python科学计算库,用于快速处理任意维度的数组。Numpy支持常见的数组和矩阵操作,对于同样的数值计算任务,使用NumPy不仅代码要简洁的多,而且NumPy的性能远远优于原生Python,基本是一个到两个数量级的差距,而且数据量越大,NumPy的优势就越明显。

Numpy最为核心的数据类型是ndarray,使用ndarray可以处理一维、二维和多维数组,该对象相当于是一个快速而灵活的大数据容器。NumPy底层代码使用C语言编写,解决了GIL的限制,ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作速度很快,远远优于Python中的list;另一方面ndarray对象提供了更多的方法来处理数据,尤其是和统计相关的方法,这些方法也是Python原生的list没有的。

准备工作

  1. 启动Notebook

    jupyter notebook

    提示:在启动Notebook之前,建议先安装好数据分析相关依赖项,包括之前提到的三大神器以及相关依赖项,包括:numpypandasmatplotlibopenpyxlxlrdxlwt等。如果使用Anaconda,则无需单独安装。

  2. 导入

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt

    说明:如果已经启动了Notebook但尚未安装相关依赖库,例如NumPy,可以在Notebook的单元格中输入!pip install numpy并运行该单元格来安装NumPy,其他库如法炮制。安装成功后选择“Kernel”(服务)菜单的“Restart”(重启)选项来重启Notebook内核(前面有讲到重启的快捷键)来使新安装的库生效。上面我们不仅导入了NumPy,还将pandas和matplotlib库一并导入了。

创建数组对象

创建ndarray对象有很多种方法,下面就如何创建一维数组、二维数组和多维数组进行说明。

一维数组

  • 方法一:使用array函数,通过list创建数组对象

    代码:

    array1 = np.array([1, 2, 3, 4, 5])
    array1

    输出:

    array([1, 2, 3, 4, 5])
    
  • 方法二:使用arange函数,指定取值范围创建数组对象

    代码:

    array2 = np.arange(0, 20, 2)
    array2

    输出:

    array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])
    
  • 方法三:使用linspace函数,用指定范围均匀间隔的数字创建数组对象

    代码:

    array3 = np.linspace(-5, 5, 101)
    array3

    输出:

    array([-5. , -4.9, -4.8, -4.7, -4.6, -4.5, -4.4, -4.3, -4.2, -4.1, -4. ,
           -3.9, -3.8, -3.7, -3.6, -3.5, -3.4, -3.3, -3.2, -3.1, -3. , -2.9,
           -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2.1, -2. , -1.9, -1.8,
           -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1. , -0.9, -0.8, -0.7,
           -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,  0. ,  0.1,  0.2,  0.3,  0.4,
            0.5,  0.6,  0.7,  0.8,  0.9,  1. ,  1.1,  1.2,  1.3,  1.4,  1.5,
            1.6,  1.7,  1.8,  1.9,  2. ,  2.1,  2.2,  2.3,  2.4,  2.5,  2.6,
            2.7,  2.8,  2.9,  3. ,  3.1,  3.2,  3.3,  3.4,  3.5,  3.6,  3.7,
            3.8,  3.9,  4. ,  4.1,  4.2,  4.3,  4.4,  4.5,  4.6,  4.7,  4.8,
            4.9,  5. ])
    
  • 方法四:使用numpy.random模块的函数生成随机数创建数组对象

    产生10个$[0, 1)$范围的随机小数,代码:

    array4 = np.random.rand(10)
    array4

    输出:

    array([0.45556132, 0.67871326, 0.4552213 , 0.96671509, 0.44086463,
           0.72650875, 0.79877188, 0.12153022, 0.24762739, 0.6669852 ])
    

    产生10个$[1, 100)$范围的随机整数,代码:

    array5 = np.random.randint(1, 101, 10)
    array5

    输出:

    array([29, 97, 87, 47, 39, 19, 71, 32, 79, 34])
    

    产生20个$\mu=50$,$\sigma=10$的正态分布随机数,代码:

    array6 = np.random.normal(50, 10, 20)
    array6

    输出:

    array([55.04155586, 46.43510797, 20.28371158, 62.67884053, 61.23185964,
           38.22682148, 53.17126151, 43.54741592, 36.11268017, 40.94086676,
           63.27911699, 46.92688903, 37.1593374 , 67.06525656, 67.47269463,
           23.37925889, 31.45312239, 48.34532466, 55.09180924, 47.95702787])
    

二维数组

  • 方法一:使用array函数,通过嵌套的list创建数组对象

    代码:

    array7 = np.array([[1, 2, 3], [4, 5, 6]])
    array7

    输出:

    array([[1, 2, 3],
           [4, 5, 6]])
    
  • 方法二:使用zerosonesfull函数指定数组的形状创建数组对象

    使用zeros函数,代码:

    array8 = np.zeros((3, 4))
    array8

    输出:

    array([[0., 0., 0., 0.],
           [0., 0., 0., 0.],
           [0., 0., 0., 0.]])
    

    使用ones函数,代码:

    array9 = np.ones((3, 4))
    array9

    输出:

    array([[1., 1., 1., 1.],
           [1., 1., 1., 1.],
           [1., 1., 1., 1.]])
    

    使用full函数,代码:

    array10 = np.full((3, 4), 10)
    array10

    输出:

    array([[10, 10, 10, 10],
           [10, 10, 10, 10],
           [10, 10, 10, 10]])
    
  • 方法三:使用eye函数创建单位矩阵

    代码:

    array11 = np.eye(4)
    array11

    输出:

    array([[1., 0., 0., 0.],
           [0., 1., 0., 0.],
           [0., 0., 1., 0.],
           [0., 0., 0., 1.]])
    
  • 方法四:通过reshape将一维数组变成二维数组

    代码:

    array12 = np.array([1, 2, 3, 4, 5, 6]).reshape(2, 3)
    array12

    输出:

    array([[1, 2, 3],
           [4, 5, 6]])
    

    提示reshapendarray对象的一个方法,使用reshape方法时需要确保调形后的数组元素个数与调形前数组元素个数保持一致,否则将会产生异常。

  • 方法五:通过numpy.random模块的函数生成随机数创建数组对象

    产生$[0, 1)$范围的随机小数构成的3行4列的二维数组,代码:

    array13 = np.random.rand(3, 4)
    array13

    输出:

    array([[0.54017809, 0.46797771, 0.78291445, 0.79501326],
           [0.93973783, 0.21434806, 0.03592874, 0.88838892],
           [0.84130479, 0.3566601 , 0.99935473, 0.26353598]])
    

    产生$[1, 100)$范围的随机整数构成的3行4列的二维数组,代码:

    array14 = np.random.randint(1, 100, (3, 4))
    array14

    输出:

    array([[83, 30, 64, 53],
           [39, 92, 53, 43],
           [43, 48, 91, 72]])
    

多维数组

  • 使用随机的方式创建多维数组

    代码:

    array15 = np.random.randint(1, 100, (3, 4, 5))
    array15

    输出:

    array([[[94, 26, 49, 24, 43],
            [27, 27, 33, 98, 33],
            [13, 73,  6,  1, 77],
            [54, 32, 51, 86, 59]],
    
           [[62, 75, 62, 29, 87],
            [90, 26,  6, 79, 41],
            [31, 15, 32, 56, 64],
            [37, 84, 61, 71, 71]],
    
           [[45, 24, 78, 77, 41],
            [75, 37,  4, 74, 93],
            [ 1, 36, 36, 60, 43],
            [23, 84, 44, 89, 79]]])
    
  • 将一维二维的数组调形为多维数组

    一维数组调形为多维数组,代码:

    array16 = np.arange(1, 25).reshape((2, 3, 4))
    array16

    输出:

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

    二维数组调形为多维数组,代码:

    array17 = np.random.randint(1, 100, (4, 6)).reshape((4, 3, 2))
    array17

    输出:

    array([[[60, 59],
            [31, 80],
            [54, 91]],
    
           [[67,  4],
            [ 4, 59],
            [47, 49]],
    
           [[16,  4],
            [ 5, 71],
            [80, 53]],
    
           [[38, 49],
            [70,  5],
            [76, 80]]])
    
  • 读取图片获得对应的三维数组

    代码:

    array18 = plt.imread('guido.jpg')

array18 ```

输出:

```
array([[[ 36,  33,  28],
        [ 36,  33,  28],
        [ 36,  33,  28],
        ...,
        [ 32,  31,  29],
        [ 32,  31,  27],
        [ 31,  32,  26]],

       [[ 37,  34,  29],
        [ 38,  35,  30],
        [ 38,  35,  30],
        ...,
        [ 31,  30,  28],
        [ 31,  30,  26],
        [ 30,  31,  25]],

       [[ 38,  35,  30],
        [ 38,  35,  30],
        [ 38,  35,  30],
        ...,
        [ 30,  29,  27],
        [ 30,  29,  25],
        [ 29,  30,  25]],

       ...,

       [[239, 178, 123],
        [237, 176, 121],
        [235, 174, 119],
        ...,
        [ 78,  68,  56],
        [ 75,  67,  54],
        [ 73,  65,  52]],

       [[238, 177, 120],
        [236, 175, 118],
        [234, 173, 116],
        ...,
        [ 82,  70,  58],
        [ 78,  68,  56],
        [ 75,  66,  51]],

       [[238, 176, 119],
        [236, 175, 118],
        [234, 173, 116],
        ...,
        [ 84,  70,  61],
        [ 81,  69,  57],
    [ 79,  67,  53]]], dtype=uint8)
```

> **说明**:上面的代码读取了当前路径下名为`guido.jpg` 的图片文件,计算机系统中的图片通常由若干行若干列的像素点构成,而每个像素点又是由红绿蓝三原色构成的,所以能够用三维数组来表示。读取图片用到了matplotlib库的`imread`函数。

数组对象的属性

  1. size属性:数组元素个数

    代码:

    array19 = np.arange(1, 100, 2)
    array20 = np.random.rand(3, 4)
    print(array19.size, array20.size)

    输出:

    50 12
    
  2. shape属性:数组的形状

    代码:

    print(array19.shape, array20.shape)

    输出:

    (50,) (3, 4)
    
  3. dtype属性:数组元素的数据类型

    代码:

    print(array19.dtype, array20.dtype)

    输出:

    int64 float64
    

    ndarray对象元素的数据类型可以参考如下所示的表格。

  4. ndim属性:数组的维度

    代码:

    print(array19.ndim, array20.ndim)

    输出:

    1 2
    
  5. itemsize属性:数组单个元素占用内存空间的字节数

    代码:

    array21 = np.arange(1, 100, 2, dtype=np.int8)
    print(array19.itemsize, array20.itemsize, array21.itemsize)

    输出:

    8 8 1
    

    说明:在使用arange创建数组对象时,通过dtype参数指定元素的数据类型。可以看出,np.int8代表的是8位有符号整数,只占用1个字节的内存空间,取值范围是$[-128,127]$。

  6. nbytes属性:数组所有元素占用内存空间的字节数

    代码:

    print(array19.nbytes, array20.nbytes, array21.nbytes)

    输出:

    400 96 50
    
  7. flat属性:数组(一维化之后)元素的迭代器

    代码:

    from typing import Iterable
    
    print(isinstance(array20.flat, np.ndarray), isinstance(array20.flat, Iterable))

    输出:

    False True
    
  8. base属性:数组的基对象(如果数组共享了其他数组的内存空间)

    代码:

    array22 = array19[:]
    print(array22.base is array19, array22.base is array21)

    输出:

    True False
    

    说明:上面的代码用到了数组的切片操作,它类似于Python中list类型的切片,但在细节上又不完全相同,下面会专门讲解这个知识点。通过上面的代码可以发现,ndarray切片后得到的新的数组对象跟原来的数组对象共享了内存中的数据,因此array22base属性就是array19对应的数组对象。

数组的索引和切片

和Python中的列表类似,NumPy的ndarray对象可以进行索引和切片操作,通过索引可以获取或修改数组中的元素,通过切片可以取出数组的一部分。

  1. 索引运算

    一维数组,代码:

    array23 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
    print(array23[0], array23[array23.size - 1])
    print(array23[-array23.size], array23[-1])

    输出:

    1 9
    1 9
    

    二维数组,代码:

    array24 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print(array24[2])
    print(array24[0][0], array24[-1][-1])
    print(array24[1][1], array24[1, 1])

    输出:

    [7 8 9]
    1 9
    5 5
    [[ 1  2  3]
     [ 4 10  6]
     [ 7  8  9]]
    

    代码:

    array24[1][1] = 10
    print(array24)
    array24[1] = [10, 11, 12]
    print(array24)

    输出:

    [[ 1  2  3]
     [ 4 10  6]
     [ 7  8  9]]
    [[ 1  2  3]
     [10 11 12]
     [ 7  8  9]]
    
  2. 切片运算

    代码:

    print(array24[:2, 1:])

    输出:

    [[2 3]
     [5 6]]
    

    代码:

    print(array24[2])
    print(array24[2, :])

    输出:

    [7 8 9]
    [7 8 9]
    

    代码:

    print(array24[2:, :])

    输出:

    [[7 8 9]]
    

    代码:

    print(array24[:, :2])

    输出:

    [[1 2]
     [4 5]
     [7 8]]
    

    代码:

    print(array24[1, :2])

    输出:

    [4 5]
    

    代码:

    print(array24[1:2, :2])

    输出:

    [[4 5]]
    

    关于数组的索引和切片运算,大家可以通过下面的两张图来增强印象,这两张图来自《利用Python进行数据分析》一书,它是pandas的作者Wes McKinney撰写的Python数据分析领域的经典教科书,有兴趣的读者可以购买和阅读原书。

数组对象的方法

统计方法

ndarray对象的统计方法主要包括:summeanstdvarminmaxargminargmaxcumsum等,分别用于对数组中的元素求和、求平均、求标准差、求方差、找最大、找最小、求累积和等,请参考下面的代码。

array25 = np.array([1, 2, 3, 4, 5, 5, 4, 3, 2, 1])
print(array25.sum())
print(array25.mean())
print(array25.max())
print(array25.min())
print(array25.std())
print(array25.var())
print(array25.cumsum())

输出:

30
3.0
5
1
1.4142135623730951
2.0
[ 1  3  6 10 15 20 24 27 29 30]

####其他方法

  1. all() / any()方法:判断数组是否所有元素都是True / 判断数组是否有为True的元素。

  2. astype()方法:拷贝数组,并将数组中的元素转换为指定的类型。

  3. dot()方法:实现一个数组和另一个数组的点乘运算。

    输出:

    
    
  4. dump()/load()方法:保存数组到文件中/从文件中加载数组。

    输出:

    
    
  5. fill()方法。

    输出:

    
    
  6. flatten()方法:将多维数组扁平化为一维数组。

    输出:

    
    
  7. nonzero()方法:返回非0元素的索引。

  8. round()方法:对数组中的元素做四舍五入操作。

  9. sort()方法:对数组进行就地排序。

    输出:

    
    
  10. swapaxes()transpose()方法:交换数组指定的轴

  11. take()方法:从数组中取指定索引的元素。

  12. tolist()方法:将数组转成Python中的list

数组的运算

标量运算

矢量运算

广播机制

矩阵运算