NumPy学习

  • Post author:
  • Post category:其他




NumPy学习



1. NumPy介绍

Numpy(Numerical Python)是一个开源的Python科学计算库,

用于快速处理任意维度的数组

Numpy

支持常见的数组和矩阵操作

。对于同样的数值计算任务,使用Numpy比直接使用Python要简洁的多。

Numpy

使用ndarray对象来处理多维数组

,该对象是一个快速而灵活的大数据容器。



2. ndarray介绍

NumPy提供了一个

N维数组类型ndarray

,它描述了

相同类型

的“items”的集合。

import numpy as np
# 创建ndarray
score = np.array(
[[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 64],
[86, 85, 83, 67, 80]])
score


3. ndarray与list运算效率对比
import random
import time
import numpy as np
a = []
for i in range(100000000):
    a.append(random.random())
# 通过%time魔法方法, 查看当前行的代码运行一次所花费的时间
%time sum1=sum(a)
b=np.array(a)
%time sum2=np.sum(b)

结果:

CPU times: user 852 ms, sys: 262 ms, total: 1.11 s
Wall time: 1.13 s
CPU times: user 133 ms, sys: 653 µs, total: 133 ms
Wall time: 134 ms

从中我们看到ndarray的计算速度要快很多,节约了时间。


机器学习的最大特点就是大量的数据运算

,那么如果没有一个快速的解决方案,那可能现在python也在机器学习领域达不到好的效果。

在这里插入图片描述

Numpy专门针对ndarray的操作和运算进行了设计,所以数组的存储效率和输入输出性能远优于Python中的嵌套列表,数组越大,Numpy的优势就越明显。



4. ndarray的优势


  1. 内存块风格
    在这里插入图片描述

    从图中我们可以看出ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作数组元素时速度更快。

    这是因为ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面Numpy的ndarray不及Python原生list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python原生list简单的多。



  2. ndarray支持并行化运算(向量化运算)

    numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算



  3. 效率远高于纯Python代码

    Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,所以,其效率远高于纯Python代码。



5. N维数组-ndarray


  1. ndarray的属性

    数组属性反映了数组本身固有的信息。

    属性名字 属性解释
    ndarray.shape 数组维度的元组
    ndarray.ndim 数组维数
    ndarray.size 数组中的元素数量
    ndarray.itemsize 一个数组元素的长度(字节)
    ndarray.dtype 数组元素的类型


  2. ndarray的形状
    # 创建不同形状的数组
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> b = np.array([1,2,3,4])
    >>> c = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]])
    >>> a.shape
    >>> b.shape
    >>> c.shape
    
    (2, 3)  # 二维数组
    (4,)    # 一维数组
    (2, 2, 3) # 三维数组
    


  3. ndarray的类型

    dtype是numpy.dtype类型,先看看对于数组来说都有哪些类型

    名称 描述 简写
    np.bool 用一个字节存储的布尔类型(True或False) ‘b’
    np.int8 一个字节大小,-128 至 127 ‘i’
    np.int16 整数,-32768 至 32767 ‘i2’
    np.int32 整数,-2^31 至 2^32 -1 ‘i4’
    np.int64 整数,-2^63 至 2^63 – 1 ‘i8’
    np.uint8 无符号整数,0 至 255 ‘u’
    np.uint16 无符号整数,0 至 65535 ‘u2’
    np.uint32 无符号整数,0 至 2^32 – 1 ‘u4’
    np.uint64 无符号整数,0 至 2^64 – 1 ‘u8’
    np.float16 半精度浮点数:16位,正负号1位,指数5位,精度10位 ‘f2’
    np.float32 单精度浮点数:32位,正负号1位,指数8位,精度23位 ‘f4’
    np.float64 双精度浮点数:64位,正负号1位,指数11位,精度52位 ‘f8’
    np.complex64 复数,分别用两个32位浮点数表示实部和虚部 ‘c8’
    np.complex128 复数,分别用两个64位浮点数表示实部和虚部 ‘c16’
    np.object_ python对象 ‘O’
    np.string_ 字符串 ‘S’
    np.unicode_ unicode类型 ‘U’


    创建数组的时候指定类型


    • 注意

      :若不指定,整数默认int64,小数默认float64
    >>> a = np.array([[1, 2, 3],[4, 5, 6]], dtype=np.float32)
    >>> a.dtype
    dtype('float32')
    >>> arr = np.array(['python', 'tensorflow', 'scikit-learn', 'numpy'], dtype = np.string_)
    >>> arr
    array([b'python', b'tensorflow', b'scikit-learn', b'numpy'], dtype='|S12')
    


  4. ndarray基本操作


    1. 生成数组的方法


      1. 生成0和1数组
        np.ones(shape, dtype)
        np.ones_like(a, dtype)
        np.zeros(shape, dtype)
        np.zeros_like(a, dtype)
        


      2. 从现有数组生成

        • np.array(object, dtype)

        • np.asarray(a, dtype)
        a = np.array([[1,2,3],[4,5,6]]) 
        # 从现有的数组当中创建
        a1 = np.array(a) # 深拷贝
        # 相当于索引的形式,并没有真正的创建一个新的
        a2 = np.asarray(a) # 浅拷贝
        


      3. 生成固定范围的数组


        • np.linspace (start, stop, num, endpoint)

          • 创建等差数组 — 指定数量
          • 参数:

            • start:序列的起始值
            • stop:序列的终止值
            • num:要生成的等间隔样例数量,默认为50
            • endpoint:序列中是否包含stop值,默认为ture
          # 生成等间隔的数组
          np.linspace(0, 100, 11)
          # 结果
          array([  0.,  10.,  20.,  30.,  40.,  50.,  60.,  70.,  80.,  90., 100.])
          


        • np.arange(start,stop, step, dtype)

          • 创建等差数组 — 指定步长
          • 参数:step:步长,默认值为1
          np.arange(10, 50, 2)
          # 结果
          array([10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42,
                 44, 46, 48])
          


        • np.logspace(start,stop, num)

          • 创建等比数列
          • 参数::num:要生成的等比数列数量,默认为50
          # 生成10^x
          np.logspace(0, 2, 3)
          # 结果
          array([  1.,  10., 100.])
          


      4. 生成随机数组


        使用模块介绍
        • np.random模块


        正态分布

        正态分布是一种概率分布。正态分布是具有两个参数μ和σ的连续型随机变量的分布,第一参数μ是服从正态分布的随机变量的均值,第二个参数σ是此随机变量的标准差,所以正态分布记作

        N(μ,σ )


        μ决定了其位置,其标准差σ

        决定了分布的幅度。当μ = 0,σ = 1时的正态分布是标准正态分布。
        在这里插入图片描述

        np.random.randn(d0, d1, …, dn)
        功能:从标准正态分布中返回一个或多个样本值
        np.random.normal(loc=0.0, scale=1.0, size=None)
        loc:float:此概率分布的均值(对应着整个分布的中心centre)
        scale:float:此概率分布的标准差(对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高)
        size:int or tuple of ints
        输出的shape,默认为None,只输出一个值
        np.random.standard_normal(size=None):返回指定形状的标准正态分布的数组。
        

        举例

        # 生成均值为1.75,标准差为1的正态分布数据,100000000个
        x1 = np.random.normal(1.75, 1, 100000000)
        # 画图看分布状况
        # 1)创建画布
        plt.figure(figsize=(20, 10), dpi=100)
        # 2)绘制直方图
        plt.hist(x1, 1000)
        # 3)显示图像
        plt.show()
        
        


        均匀分布
        np.random.rand(d0, d1, ..., dn)
        返回[0.0,1.0)内的一组均匀分布的数。
        np.random.uniform(low=0.0, high=1.0, size=None)从
        一个均匀分布[low,high)中随机采样,注意定义域是左闭右开,即包含low,不包含high.
        参数介绍:
            low: 采样下界,float类型,默认值为0;
            high: 采样上界,float类型,默认值为1;
            size: 输出样本数目,为int或元组(tuple)类型,例如,size=(m,n,k), 则输出mnk个样本,缺省时输出1个值。
        返回值:ndarray类型,其形状和参数size中描述一致。
        np.random.randint(low, high=None, size=None, dtype='l')
        从一个均匀分布中随机采样,生成一个整数或N维整数数组,
        取数范围:若high不为None时,取[low,high)之间随机整数,否则取值[0,low)之间随机整数。
        
        

        举例

        import matplotlib.pyplot as plt
        # 生成均匀分布的随机数
        x2 = np.random.uniform(-1, 1, 100000000)
        # 画图看分布状况
        # 1)创建画布
        plt.figure(figsize=(10, 10), dpi=100)
        # 2)绘制直方图
        plt.hist(x=x2, bins=1000)  # x代表要使用的数据,bins表示要划分区间数
        # 3)显示图像
        plt.show()
        
        


    2. 数组的索引、切片
      • 直接进行索引,切片
      • 对象[:, :] – 先行后列

      举例

      stock_change = np.random.normal(0, 1, (4, 5))
      stock_change
      # 结果
      array([[ 1.01365019,  0.42216968, -1.15537791, -0.35097744, -0.85219823],
             [-0.00678194, -0.68900579,  0.52490674, -0.92782014, -0.558097  ],
             [-0.85191509,  0.42078045, -1.1952849 ,  0.11857293, -0.67293944],
             [ 0.68247205, -1.29717521, -1.21356833,  1.06368909, -3.32126045]])
      
      stock_change[0, 0:3]
      # 结果
      array([ 1.01365019,  0.42216968, -1.15537791])
      stock_change[0, 1]
      # 结果
      0.4221696766107992
      
      


    3. 形状修改


      1. ndarray.reshape(shape, order)
        • 返回一个具有相同数据域,但shape不一样的

          视图
        • 行、列不进行互换,只是新的排序
        • 产生新的对象


      2. ndarray.resize(new_shape)
        • 修改数组本身的形状(需要保持元素个数前后相同)
        • 行、列不进行互换


      3. ndarray.T
        • 数组的转置
        • 将数组的行、列进行互换
      # 返回一个具有相同数据域,但shape不一样的视图
      # 在转换形状的时候,一定要注意数组的元素匹配
      stock_change.reshape([5, 4])
      stock_change.reshape([-1,10])  # 数组的形状被修改为: (2, 10), -1: 表示通过待计算
      # 修改数组本身的形状,行、列不进行互换
      stock_change.resize([5, 4])
      # 查看修改后结果(5, 4)
      stock_change.shape
      # 数组的行、列进行互换
      stock_change.T.shape # (4, 5)
      
      


    4. 类型修改


      1. ndarray.astype(type)
        • 返回修改了类型之后的数组

          stock_change.astype(np.int32)
          
          


      2. ndarray.tostring([order])或者ndarray.tobytes([order])
        • 构造包含数组中原始数据字节的Python字节

          arr = np.array([[[1, 2, 3], [4, 5, 6]], [[12, 3, 34], [5, 6, 7]]])
          arr.tostring()
          
          


      3. jupyter输出太大可能导致崩溃问题

        如果遇到

        IOPub data rate exceeded.
            The notebook server will temporarily stop sending output
            to the client in order to avoid crashing it.
            To change this limit, set the config variable
            `--NotebookApp.iopub_data_rate_limit`.
        
        

        这个问题是在jupyer当中对输出的字节数有限制,需要去修改配置文件

        创建配置文件

        jupyter notebook --generate-config
        vi ~/.jupyter/jupyter_notebook_config.py
        
        

        取消注释,多增加

        ## (bytes/sec) Maximum rate at which messages can be sent on iopub before they
        #  are limited.
        c.NotebookApp.iopub_data_rate_limit = 10000000
        
        


        但是不建议这样去修改,jupyter输出太大会崩溃



    5. 数组的去重


      • np.unique(对象)
        temp = np.array([[1, 2, 3, 4],[3, 4, 5, 6]])
        >>> np.unique(temp)
        # 结果
        array([1, 2, 3, 4, 5, 6])
        


6. Ndarray运算


  1. 逻辑运算

    # 生成10名同学,5门功课的数据
    >>> score = np.random.randint(40, 100, (10, 5))
    # 取出最后4名同学的成绩,用于逻辑判断
    >>> test_score = score[6:, 0:5]
    # 逻辑判断, 如果成绩大于60就标记为True 否则为False
    >>> test_score > 60
    array([[ True,  True,  True, False,  True],
           [ True,  True,  True, False,  True],
           [ True,  True, False, False,  True],
           [False,  True,  True,  True,  True]])
    # BOOL赋值, 将满足条件的设置为指定的值-布尔索引
    >>> test_score[test_score > 60] = 1
    >>> test_score
    array([[ 1,  1,  1, 52,  1],
           [ 1,  1,  1, 59,  1],
           [ 1,  1, 44, 44,  1],
           [59,  1,  1,  1,  1]])
    


  2. 通用判断函数


    • np.all()
      # 判断前两名同学的成绩[0:2, :]是否全及格
      >>> np.all(score[0:2, :] > 60)
      False
      


    • np.any()
      # 判断前两名同学的成绩[0:2, :]是否有大于90分的
      >>> np.any(score[0:2, :] > 80)
      True
      


  3. np.where(三元运算符)

    通过使用np.where能够进行更加复杂的运算

    • np.where()
    # 判断前四名学生,前四门课程中,成绩中大于60的置为1,否则为0
    temp = score[:4, :4]
    np.where(temp > 60, 1, 0)
    
    • 复合逻辑需要结合np.logical_and和np.logical_or使用
    # 判断前四名学生,前四门课程中,成绩中大于60且小于90的换为1,否则为0
    np.where(np.logical_and(temp > 60, temp < 90), 1, 0)
    
    # 判断前四名学生,前四门课程中,成绩中大于90或小于60的换为1,否则为0
    np.where(np.logical_or(temp > 90, temp < 60), 1, 0)
    


  4. 统计运算


    • 统计指标
      在数据挖掘/机器学习领域,统计指标的值也是我们分析问题的一种方式。常用的指标如下:
      min(a, axis):返回数组的最小值或沿轴的最小值
      max(a, axis]):返回数组的最小值或沿轴的最大值
      median(a, axis):沿着指定的轴计算中值
      mean(a, axis, dtype):沿着指定的轴计算算术平均值
      std(a, axis, dtype):计算沿指定轴的标准偏差
      var(a, axis, dtype):沿指定轴计算方差
      


    • 案例

      进行统计的时候,

      axis 轴的取值并不一定,Numpy中不同的API轴的值都不一样,在这里,axis 0代表列, axis 1代表行去进行统计

      # 接下来对于前四名学生,进行一些统计运算
      # 指定列 去统计
      temp = score[:4, 0:5]
      print("前四名学生,各科成绩的最大分:{}".format(np.max(temp, axis=0)))
      print("前四名学生,各科成绩的最小分:{}".format(np.min(temp, axis=0)))
      print("前四名学生,各科成绩波动情况:{}".format(np.std(temp, axis=0)))
      print("前四名学生,各科成绩的平均分:{}".format(np.mean(temp, axis=0)))
      

      结果:

      前四名学生,各科成绩的最大分:[96 97 72 98 89]
      前四名学生,各科成绩的最小分:[55 57 45 76 77]
      前四名学生,各科成绩波动情况:[16.25576821 14.92271758 10.40432602  8.0311892   4.32290412]
      前四名学生,各科成绩的平均分:[78.5  75.75 62.5  85.   82.25]
      

      如果需要统计出某科最高分对应的是哪个同学?

      • np.argmax(temp, axis=)
      • np.argmin(temp, axis=)
      print("前四名学生,各科成绩最高分对应的学生下标:{}".format(np.argmax(temp, axis=0)))
      
      

      结果:

      前四名学生,各科成绩最高分对应的学生下标:[0 2 0 0 1]
      
      


  5. 数组与数的运算
    arr = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
    arr + 1
    arr / 2
    # 结果
    array([[2, 3, 4, 3, 2, 5], [6, 7, 2, 3, 4, 2]])
    array([[0.5, 1. , 1.5, 1. , 0.5, 2. ], [2.5, 3. , 0.5, 1. , 1.5, 0.5]])
    # 可以对比python列表的运算,看出区别
    a = [1, 2, 3, 4, 5]
    a * 3
    # 结果
    [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
    
    


  6. 数组与数组的运算

    数组在进行矢量化运算时,

    要求数组的形状是相等的

    。当形状不相等的数组执行算术运算的时候,就会出现广播机制,该机制会对数组进行扩展,使数组的shape属性值一样,这样,就可以进行矢量化运算了。下面通过一个例子进行说明:

    arr1 = np.array([[0],[1],[2],[3]])
    arr1.shape
    # (4, 1)
    arr2 = np.array([1,2,3])
    arr2.shape
    # (3,)
    arr1+arr2
    # 结果是:
    array([[1, 2, 3],
           [2, 3, 4],
           [3, 4, 5],
           [4, 5, 6]])
    
    

    上述代码中,数组arr1是4行1列,arr2是1行3列。这两个数组要进行相加,按照广播机制会对数组arr1和arr2都进行扩展,使得数组arr1和arr2都变成4行3列。

    下面通过一张图来描述广播机制扩展数组的过程:
    在这里插入图片描述

    广播机制实现了时两个或两个以上数组的运算,即使这些数组的shape不是完全相同的,只需要满足如下任意一个条件即可。


    • 数组的某一维度等长


    • 其中一个数组的某一维度为

      1 。

    广播机制需要

    扩展维度小的数组

    ,使得它与维度最大的数组的shape值相同,以便使用元素级函数或者运算符进行运算。如果是下面这样,则不匹配:

    A  (1d array): 10
    B  (1d array): 12
    A  (2d array):      2 x 1
    B  (3d array):  8 x 4 x 3
    
    

    数组运算,满足广播机制,就可以进行运算

    • 维度相等
    • shape(其中对应的地方为1,也是可以的)



版权声明:本文为weixin_45439324原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。