• Numpy那些事


    一、引言

    • Numpy(Numerical Python)是一个开源的Python科学计算库,它的出现让我们可以更加方便的使用数组、进行矩阵运算,还提供了大量的数学函数库供使用者直接调用。
    • 对于同样的数值运算任务,使用numpy要比直接写python代码具有更简洁的代码和更高效的性能,而且numpy是sklearn、tensorflow等各大数据科学框架的基础库,对于numpy的学习对于我们进一步理解这些库具有非常大的帮助。
    • numpy的学习,以读懂为首要目的,争取快速入坑(建议亲自动手敲一遍代码),所有相关的操作不用死记硬背,用时再查。
    ## numpy安装
    # pip install Numpy
    import numpy as np
    np.__version__
    
    • 1
    • 2
    • 3
    • 4

    二、创建array对象

    2.1 从其它数据类型创建array

    # 从Python的列表创建array
    ## 一维数组
    arr1 = np.array([0,2,4,6,8])
    ## 二维数组
    arr2 = np.array(
        [
            [0,2,4,6,8],
            [1,3,5,7,9]
        ]
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.1 从其它数据类型直接创建array

    # 从其它库函数数据创建array
    from PIL import Image  ## 也可以借助cv2
    
    image_dog=Image.open('./images/dog.png')  
    print(type(image_dog))
    image_dog_np=np.array(image_dog) 
    print(type(image_dog_np)) 
    print(image_dog_np.shape)  ## 打印数组的维度
    print(image_dog_np.dtype)  ## 打印ndarray对象的元素类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    打印结果:
    在这里插入图片描述

    2.2 借助numpy的预定函数如:arange、ones、empty等进行创建

    # 使用np.arange创建数组
    array_arange = np.arange(0,10,2)    ## 创建0-10步数为2的数组,用过Matlab的同学应该很熟悉
    
    # 使用np.zeros创建全零数组
    array_zeros = np.zeros((2,3))    ## 创建2行3列的全零数组
    
    # 使用np.full创建指定值的数组
    array_full = np.full((2,2),"polars")  ## 注意numpy的array同样能够容纳str类型的数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    打印结果:
    在这里插入图片描述

    # 使用np.empty创建一个指定形状和数据类型且未初始化的数组:
    array_empty = np.empty([3,2], dtype = float) 
    ## 注:此方法得到的array数据都是未初始化的,这意味着里面的值是不确定的值,未明确赋值前尽量不要用
    
    • 1
    • 2
    • 3

    tips:

    • 除了以上所列函数意外,还有诸如linspace、logspace、ones_like等函数,根据自己所需灵活取用即可。
    • numpy中数组的所有元素类型必须是唯一的,它本质上是 dtype 对象的实例,并对应唯一的字符。

    2.3 使用random模块生成随机数的数组

    # 使用np.random.random创建数组
    array_random = np.random.random((3,2))  ## 创建3行2列的数组,里面的值是0-1之间的随机数
    
    • 1
    • 2

    案例1:随机漫步

    一个简单的数组创建的例子:从0开始,已知步长1和-1出现的概率相等,通过各种方式实现1000步的随机漫步。

    %%time
    # (1)通过内置的random模块以纯Python的方式实现
    import random 
    position = 0
    walk = [position]
    steps = 1000
    for i in range(steps):
        step = 1 if random.randint(0, 1) else -1
        position += step
        walk.append(position)
    # 画出折线图
    import matplotlib.pyplot as plt
    plt.plot(walk[:100])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    %%time是一个魔术命令,它是IPython的一部分,可以用来打印整个单元格的执行时间。
    在这里插入图片描述

    %%time
    # (2)用np.random模块一次性随机产生
    nsteps = 1000
    draws = np.random.randint(0, 2, size=nsteps)
    steps = np.where(draws > 0, 1, -1)
    walk = steps.cumsum()
    plt.plot(walk[:100])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    对比一下不难发现,相同的问题,基于NumPy的数据处理速度要比纯Python快10到100倍(甚至更快),并且使用的内存更少。

    三、Numpy基本运算

    3.1 数组的变形

    # 将数字 1~6 放入一个 2×3 的矩阵中
    grid = np.arange(1, 7).reshape((2, 3))  
    
    • 1
    • 2

    在这里插入图片描述

    # 矩阵的转置
    grid.T   
    
    • 1
    • 2

    在这里插入图片描述

    3.2 数组的运算

    # 一维矩阵运算
    a = np.array([10,20,30,40])
    b = np.arange(4)
    print(a,b)
    print("a+b:",a+b)
    print("a-b:",a-b)
    print("a*b:",a*b)  # 对应项相乘,若a和b大小不同,则会触发广播机制
    print("a.*b:",a.dot(b))  # 向量点击 , 等价于np.dot(a, b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    # 二维矩阵运算
    a = np.random.randint(0, 10, size = (4, 5))
    b = np.random.randint(0, 10, size = (5, 3))
    print(np.dot(a, b))   # 此时进行的是矩阵乘法
    print("the shape of a.dot(b) is " + str(np.dot(a, b).shape))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    3.3 统计运算

    arr = np.random.randn(5, 4)  # 正态分布随机数据
    print(arr)
    print('平均值:',np.mean(arr))   ## 等价于arr.mean()
    print('求和:',np.sum(arr))     ## 等价于arr.sum()
    print('最大值:',np.max(arr))    ## 等价于arr.max()
    print('最小值:',np.min(arr))    ## 等价于arr.min()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    案例2(转):利用numpy数组实现神经网络

    • 原文链接:https://blog.csdn.net/lianwaiyuwusheng/article/details/109517997

    这个案例有一定门槛,理论上需要对感知机(BP神经网络)有所了解,但是啃下来后则非常有助于之后复现有关的公式,有条件还是建议试试看。

    """
    1. 获取输入数据和标签
    2. 定义网络,前向传播得到输出
    3. 定义损失函数,
    4. 训练,反向传播更新网络参数
    """
    
    import numpy as np
    
    N, D_in, H, D_out = 64, 1000, 100, 10
    
    # 输入x和标签y
    x = np.random.randn(N, D_in)
    y = np.random.randn(N, D_out)
    
    # 初始化参数
    w1 = np.random.randn(D_in, H)
    w2 = np.random.randn(H, D_out)
    
    learning_rate = 1e-6
    
    for t in range(500):
        # 前向传播 batch_size=all
        h = x.dot(w1)
        h_relu = np.maximum(h, 0)
        y_pred = h_relu.dot(w2)
    
        # 损失函数
        loss = np.square(y_pred - y).sum()
        if t % 100 == 99:print(t, loss)
    
        # 反向传播
        grad_y_pred = 2.0 * (y_pred - y)
        grad_w2 = h_relu.T.dot(grad_y_pred) # l=s(y) y=f(x)  J=[y_dim*x_dim]; grad l/x=sum[grad(l/y)*grad(y/x)] =J^T*grad y
        grad_h_relu = grad_y_pred.dot(w2.T)
        grad_h = grad_h_relu.copy()
        grad_h[h < 0] = 0
        grad_w1 = x.T.dot(grad_h)
    
        # 更新参数
        w1 -= learning_rate * grad_w1
        w2 -= learning_rate * grad_w2
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    四、索引与切片

    4.1 常规用法

    # 一维数组
    a1 = np.arange(10)
    print(a1)
    print("_____________________")
    print("获取第五个元素:",a1[4])   ## 取单个元素
    print("获取第五到六的元素:",a1[4:6])  ## 切片
    print("按照两步等距取样:",a1[::2])  ## 按照固定步长
    print("取出最后一个元素:",a1[-1])   ## 使用负数作为索引,这里返回最后一个
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    # 多维数组
    a2 = np.random.randint(0,10,size=(4,6))
    print(a2)
    print("_____________________")
    print("获取第一行元素:\n",a2[0])  #获取指定行元素
    print("获取第二列元素:",a2[:,1])  #获取指定列元素
    print("获取第三行第二列元素:",a2[2,1]) #获取特定位置元素
    print("获取第一行第四列、第二行第五列的元素:",a2[[0,1],[3,4]])  #获取多个指定位置元素 
    print("获取第二列、第四列的元素:\n",a2[:,[1,3]])  #获取多个指定列的全部数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    4.2 进阶用法

    # 布尔索引
    a3 = np.arange(24).reshape((4,6))
    print(a3<10)
    print(a3[a3<10])
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    # 花式索引(利用整数数组进行索引)
    a4  = np.arange(12)
    i = np.array([1,1,3,8,5]) 
    print(a4[i])
    j = np.array([[3,4],[9,7]])
    print(a4[j])  # 最终返回的格式跟j一致
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    # 对一个数组中任意两行做交换
    A = np.arange(25).reshape(5,5)
    A[[0,1]] = A[[1,0]]
    print("交换前两行后:\n",A)
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    案例3:利用numpy数组计算一张图片所包含的颜色数量

    from PIL import Image  
    image=Image.open('./images/dog.png')  
    print(type(image))
    image=np.array(image) 
    F = image[...,0]*(256*256) + image[...,1]*256 + image[...,2]  #可以思考下为啥要这么处理
    number_color = len(np.unique(F))
    print(number_color)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    案例4:利用numpy数组实现Game of Life

    康威生命游戏

    def iterate(Z):
        # Count neighbours
        N = (Z[0:-2,0:-2] + Z[0:-2,1:-1] + Z[0:-2,2:] +
             Z[1:-1,0:-2]                + Z[1:-1,2:] +
             Z[2:  ,0:-2] + Z[2:  ,1:-1] + Z[2:  ,2:])
    
        # Apply rules
        birth = (N==3) & (Z[1:-1,1:-1]==0)
        survive = ((N==2) | (N==3)) & (Z[1:-1,1:-1]==1)
        Z[...] = 0
        Z[1:-1,1:-1][birth | survive] = 1
        return Z
    
    Z = np.random.randint(0,2,(20,20))
    itera = 1000
    for i in range(itera): 
        Z = iterate(Z)
    print(Z)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    五、广播

    numpy数组间的基础运算是一对一,也就是a.shape==b.shape,但是当两者不一样的时候,就会自动触发广播机制,数组的广播原则如下:

    • 规则 1:如果两个数组的维度数不相同,那么小维度数组的形状将 会在最左边补 1。
    • 规则 2:如果两个数组的形状在任何一个维度上都不匹配,那么数 组的形状会沿着维度为 1 的维度扩展以匹配另外一个数组的形状。
    • 规则 3:如果两个数组的形状在任何一个维度上都不匹配并且没有 任何一个维度等于 1,那么会引发异常。
    # 数组与数组运算
    a = np.array([[ 0, 0, 0],
               [10,10,10],
               [20,20,20],
               [30,30,30]])
    b = np.array([0,1,2])
    print(a+b)  # 对b的[0,1,2]行重复3次,再与a相加
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    # 数组与数字运算
    arr = np.arange(15).reshape(3,5)
    #数组中的所有元素都乘2
    print(arr*2)
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    案例5:减去数组的每个列的平均值

    sample = np.arange(15).reshape(3,5)
    print(sample)
    print("_____________________")
    print("减去每列的平均值后:")
    mu = sample.mean(axis=0)
    result = sample - mu
    print(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    # 更进一步:标准化每个列,使每个单元格相对于其各自的列具有z-score:
    (sample - sample.mean(axis=0)) / sample.std(axis=0)
    
    • 1
    • 2

    在这里插入图片描述

    六、数组操作

    6.1 数组形状的改变

    # reshape与resize,改变数组形状
    a1 = np.random.randint(0,10,size=(3,4))
    print(a1)
    print("_____________________")
    print("修改为两行六列:")
    reshape_a1 = a1.reshape((2,6))  # reshape是将数组转换成指定的形状,然后返回转换后的结果,对于原数组的形状是不会发生改变的
    print(reshape_a1)
    print("修改为四行三列:")
    a1.resize((4,3)) # resize是将数组转换成指定的形状,会直接修改数组本身,并且不会返回任何值
    print(a1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    #  将多维数组转换为一维数组(扁平化)
    a2 = np.arange(15).reshape((5, 3))
    print(a2)
    print("_____________________")
    a2_flatten = a2.flatten()  # 等价于a2.ravel()
    print("拉伸后:")
    print(a2_flatten)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    6.2 数组的叠加

    '''
    vstack代表在垂直方向叠加,如果想要叠加成功,那么列数必须一致
    hstack代表在水平方向叠加,如果想要叠加成功,那么行数必须一致
    concatenate可以手动的指定axis参数具体在哪个方向叠加
    #(1)如果axis=0,代表在水平方向叠加
    #(2)如果axis=1,代表在垂直方向叠加
    #(3)如果axis=None,会先进行叠加,再转化为1维数组
    '''
    vstack1 = np.random.randint(0,10,size=(3,4))
    print('vstack1:\n',vstack1)
    vstack2 = np.random.randint(0,10,size=(2,4))
    print('vstack2:\n',vstack2)
    #垂直方向叠加的两种方式
    vstack3 = np.vstack([vstack1,vstack2])  # 等价于np.concatenate([vstack1,vstack2],axis=0)
    print('vstack1与vstack2垂直方向叠加:\n',vstack3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    h1 = np.random.randint(0,10,size=(3,4))
    print('h1:\n',h1)
    h2 = np.random.randint(0,10,size=(3,1))
    print('h2:\n',h2)
    
    #水平方向叠加的两种方式
    h3 = np.hstack([h1,h2])  # 等价于np.concatenate([h2,h1],axis=1)
    print('h1与h2水平方向叠加:\n',h3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    七、其它

    7.1 torch与NumPy之间的转换

    import torch
    import numpy as np
    
    ### numpy to tensor
    npy	= np.random.rand(2,3)
    tor = torch.from_numpy(npy) 
    print("Type: {}".format(tor.type()))
    print("Shape/size: {}".format(tor.shape))
    print("Values:\n{}".format(tor))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    ### tensor to numpy
    tor_one = torch.ones(6)
    npy_one = tor_one.numpy()
    print("Type: {}".format(npy_one.dtype))
    print("Shape/size: {}".format(npy_one.shape))
    print("Values:\n{}".format(npy_one))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    7.2 NumPy文件操作

    # 将数组保存到文件中
    '''
    函数:np.savetxt(frame,array,fmt="%.18e",delimiter=None)
    参数说明:
    · frame:文件、字符串或产生器,可以是.gz或.bz2的压缩文件
    · array:存入文件的数组
    · fmt:写入文件的格式,例如:%d %.2f %.18e
    · delimter:分割字符串,默认是空格
    '''
    
    from PIL import Image  
    image=Image.open('./images/dog.png')  
    print(type(image))
    image_flatten=np.array(image).flatten()
    np.savetxt("../data/image.csv",image_flatten,fmt="%d",delimiter=",")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    # 读取文件
    '''
    函数:np.loadtxt(frame,dtype=np.float,delimiter=None,unpack=False)
    参数说明:
    · frame:文件、字符串或产生器,可以是.gz或.bz2的压缩文件
    · dtype:数据类型,可选
    · delimiter:分割字符串,默认是任何空格
    · skiprows:跳过前面x行
    · usecols:读取指定的列,用元组组合
    · unpack:如果True,读取出来的数组是转置后的
    '''
    #读取csv文件
    image_np = np.loadtxt("../data/image.csv",dtype='uint8',delimiter=",")
    image = image_np.reshape(700, 639, 3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    参考链接

    • NumPy菜鸟教程: https://www.runoob.com/numpy/numpy-tutorial.html
    • NumPy官网: http://www.numpy.org/
    • NumPy中文网:https://www.numpy.org.cn/article/basics/understanding_numpy.html
  • 相关阅读:
    《士兵突击》哪些最精彩的话语
    c语言中的fread
    c++23中的新功能之十四输入输出指针
    基于C#的图书管理系统数据库设计报告
    Android学习笔记 50. Android 多媒体技术——SoundPool播放音效
    C++基础(二)
    Conformer Encoder GPU 加速策略较全面汇总
    DataFrame基础知识
    Spring基础:注解进行自动注入
    个人商业模式,如何让自己变得值钱
  • 原文地址:https://blog.csdn.net/qq_39354108/article/details/126117167